diff --git a/appConfig.json b/appConfig.json deleted file mode 100644 index bc9bec14e..000000000 --- a/appConfig.json +++ /dev/null @@ -1,24 +0,0 @@ - { - "//":"PLEASE! Do not edit this file directly", - "//":" Modify it at app-template/", - - - "name": "copay", - "nameNoSpace": "copay", - "nameCase": "Copay", - "nameCaseNoSpace": "Copay", - "url": "https://copay.io", - "appDescription": "Copay Bitcoin Wallet", - "winAppName": "CopayWallet", - "wpPublisherId": "{31cdd08b-457c-413d-b440-f6665eec847d}", - "wpProductId": "{5381aa50-9069-11e4-84cc-293caf9cbdc8}", - "description": "A Secure Bitcoin Wallet", - "version": "2.5.0", - "androidVersion": "115", - "_extraCSS": null, - "_enabledExtensions": { - "coinbase": true, - "glidera": true, - "amazon": true - } -} diff --git a/browser-extensions/chrome/copay-chrome-extension.zip b/browser-extensions/chrome/copay-chrome-extension.zip deleted file mode 100644 index cd1ba0a72..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension.zip and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/css/copay.css b/browser-extensions/chrome/copay-chrome-extension/css/copay.css deleted file mode 100644 index 9ec700a79..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/css/copay.css +++ /dev/null @@ -1,3020 +0,0 @@ -.button, button { - padding: 1rem 1.2rem 1.0625rem; - border: 1px solid transparent; - font-family: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif; } - -.button.outline { - background: transparent; } - .button.outline:hover, .button.outline:focus { - background: transparent; } - -button.outline { - background: transparent; } - button.outline:hover, button.outline:focus { - background: transparent; } - -.button.outline.tiny { - background: transparent; } - .button.outline.tiny:hover, .button.outline.tiny:focus { - background: transparent; } - -button.outline.tiny { - background: transparent; } - button.outline.tiny:hover, button.outline.tiny:focus { - background: transparent; } - -.button.outline.dark-gray { - background-color: transparent; - border: 1px solid #A5B2BF; - color: #A5B2BF; } - .button.outline.dark-gray:hover, .button.outline.dark-gray:focus { - background-color: transparent; - border: 1px solid #A5B2BF; - color: #A5B2BF; } - -button.outline.dark-gray { - background-color: transparent; - border: 1px solid #A5B2BF; - color: #A5B2BF; } - button.outline.dark-gray:hover, button.outline.dark-gray:focus { - background-color: transparent; - border: 1px solid #A5B2BF; - color: #A5B2BF; } - -.button.outline.light-gray { - background-color: transparent; - border: 1px solid #CED5DC; - color: #7A8C9E; - font-size: 12px; } - .button.outline.light-gray:hover, .button.outline.light-gray:focus { - background-color: transparent; - border: 1px solid #CED5DC; - color: #7A8C9E; } - -button.outline.light-gray { - background-color: transparent; - border: 1px solid #CED5DC; - color: #7A8C9E; } - button.outline.light-gray:hover, button.outline.light-gray:focus { - background-color: transparent; - border: 1px solid #CED5DC; - color: #7A8C9E; } - -.button.outline.white { - background-color: transparent; - border: 1px solid #fff; - color: #fff; } - .button.outline.white:hover, .button.outline.white:focus { - background-color: transparent; - border: 1px solid #fff; - color: #fff; } - -button.outline.white { - background-color: transparent; - border: 1px solid #fff; - color: #fff; } - button.outline.white:hover, button.outline.white:focus { - background-color: transparent; - border: 1px solid #fff; - color: #fff; } - -button.secondary { - background-color: #008CC1; - color: #fff; } - button.secondary:hover, button.secondary:focus { - background-color: #008CC1; - color: #fff; } - -/* SECONDARY */ -.button.secondary { - background-color: #008CC1; - color: #fff; } - .button.secondary:hover, .button.secondary:focus { - background-color: #008CC1; - color: #fff; } - -/* PRIMARY */ -button.primary { - background-color: #1ABC9C; - color: #fff; } - button.primary:hover, button.primary:focus { - background-color: #1ABC9C; - color: #fff; } - -.button.primary { - background-color: #1ABC9C; - color: #fff; } - .button.primary:hover, .button.primary:focus { - background-color: #1ABC9C; - color: #fff; } - -/* WARNING */ -button.warning, .button.warning { - background-color: #ED4A43; - color: #fff; } - -button.warning:hover, button.warning:focus { - background-color: #ED4A43; - color: #fff; } - -.button.warning:hover, .button.warning:focus { - background-color: #ED4A43; - color: #fff; } - -/* WHITE */ -button.white { - background-color: #fff; - color: #2C3E50; } - button.white:hover, button.white:focus { - background-color: #fff; - color: #2C3E50; } - -.button.white { - background-color: #fff; - color: #2C3E50; } - .button.white:hover, .button.white:focus { - background-color: #fff; - color: #2C3E50; } - -/* BLACK */ -button.black { - background-color: #2C3E50; - color: #fff; } - button.black:hover, button.black:focus { - background-color: #2C3E50; - color: #fff; } - -.button.black { - background-color: #2C3E50; - color: #fff; } - .button.black:hover, .button.black:focus { - background-color: #2C3E50; - color: #fff; } - -/* GRAY */ -button.gray { - background-color: #A9B2B8; - color: #2C3E50; } - button.gray:hover, button.gray:focus { - background-color: #A9B2B8; - color: #2C3E50; } - -.button.gray { - background-color: #A9B2B8; - color: #2C3E50; } - .button.gray:hover, .button.gray:focus { - background-color: #A9B2B8; - color: #2C3E50; } - -button.disabled, button[disabled] { - border-color: transparent !important; - background-color: #A5B2BF !important; - color: #fff !important; } - -.button { - text-transform: uppercase; - transition: none !important; } - .button.disabled, .button[disabled] { - border-color: transparent !important; - background-color: #A5B2BF !important; - color: #fff !important; } - -button { - text-transform: uppercase; - transition: none !important; } - -.button:focus, button:focus { - outline: 0; } - -.postfix.button, .prefix.button { - position: absolute; - width: 35px; - height: 22px; - right: 7px; - top: 5px; - -moz-box-shadow: none; - box-shadow: none; - font-size: 12px; - border-radius: 2px; - line-height: 2; - padding: 0; - font-weight: 500; } - -.postfix.button i, .prefix.button i { - left: 12px; - top: 0; - border: none; - -moz-box-shadow: none; - box-shadow: none; - color: #fff; } - -a.postfix { - height: 34px; - border: none; - font-weight: 700; - font-size: 14px; - color: #7A8C9E; - text-transform: uppercase; - position: absolute; - top: 0; - right: 0; - width: 50px; - padding-top: 7px; } - -a.button.postfix { - color: #fff; } - -.backup .panel { - padding: 0.5rem; } - -.backup button.words { - background: #FFFFFF; - box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.3); - color: #4B6178; - text-transform: lowercase; - font-size: 0.8rem; - margin: 5px; - padding: 0.5rem; } - -.backup button[disabled] { - box-shadow: none; } - -button.radius, .button.radius { - -webkit-border-radius: 3px; - border-radius: 3px; } - -.button.small.side-bar { - padding: 0rem 0.4rem; } - -.button-box { - position: fixed; - bottom: 0; - left: 0; - width: 100%; - padding: 0.8rem; - z-index: 1; } - -.backup .button-box { - background: #F6F7F9; } - -.splash .button-box { - background: #2C3E50; } - -input { - border-radius: 2px; - background: #EDEDED; - color: #2C3E42; - padding: 1.2rem 0.7rem; - margin-bottom: 1.5rem; - border: 0; } - input[type="color"], input[type="date"], input[type="datetime-local"], input[type="datetime"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"] { - color: #B7C2CD; - margin-bottom: 1.5rem; - height: 35px; - background: transparent; - border: none; - padding-left: 0.1rem; - font-size: 13px; - border-bottom: 1px solid #E9EDF0; } - -textarea { - color: #B7C2CD; - margin-bottom: 1.5rem; - height: 35px; - background: transparent; - border: none; - padding-left: 0.1rem; - font-size: 13px; - border-bottom: 1px solid #E9EDF0; } - -input[type="text"]:focus, input[type="password"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="week"]:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="color"]:focus { - color: #4B6178; - border-color: #CED5DC; - background: transparent; } - -textarea:focus { - color: #4B6178; - border-color: #CED5DC; - background: transparent; } - -input[type="text"][disabled], input[type="text"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="text"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="password"][disabled], input[type="password"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="password"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="date"][disabled], input[type="date"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="date"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="datetime"][disabled], input[type="datetime"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="datetime"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="datetime-local"][disabled], input[type="datetime-local"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="datetime-local"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="month"][disabled], input[type="month"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="month"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="week"][disabled], input[type="week"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="week"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="email"][disabled], input[type="email"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="email"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="number"][disabled], input[type="number"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="number"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="search"][disabled], input[type="search"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="search"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="tel"][disabled], input[type="tel"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="tel"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="time"][disabled], input[type="time"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="time"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="url"][disabled], input[type="url"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="url"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -input[type="color"][disabled], input[type="color"][readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] input[type="color"] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -textarea[disabled], textarea[readonly] { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -fieldset[disabled] textarea { - background-color: #E4E8EC; - color: #2C3E50; - padding-left: 0.5rem; - opacity: 1; } - -select { - background-color: transparent; - color: #7A8C9E; - border-color: #A5B2BF; } - -label { - text-transform: uppercase; - font-weight: 700; - font-size: 11px; - color: #34495E; - margin-bottom: 3px; } - -label small { - font-size: 10px; - color: #999; - text-transform: none; } - label small.has-error { - font-size: 11px; } - -input { - outline: 0; - opacity: 1; - /*CSS transitions*/ - -o-transition-property: none !important; - -moz-transition-property: none !important; - -ms-transition-property: none !important; - -webkit-transition-property: none !important; - transition-property: none !important; - /*CSS transforms*/ - -o-transform: none !important; - -moz-transform: none !important; - -ms-transform: none !important; - -webkit-transform: none !important; - transform: none !important; - /*CSS animations*/ - -webkit-animation: none !important; - -moz-animation: none !important; - -o-animation: none !important; - -ms-animation: none !important; - animation: none !important; - /*CSS box-shadow*/ - -webkit-box-shadow: none !important; - -moz-box-shadow: none !important; - box-shadow: none !important; } - input[type="color"], input[type="date"], input[type="datetime-local"], input[type="datetime"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"] { - outline: 0; - opacity: 1; - /*CSS transitions*/ - -o-transition-property: none !important; - -moz-transition-property: none !important; - -ms-transition-property: none !important; - -webkit-transition-property: none !important; - transition-property: none !important; - /*CSS transforms*/ - -o-transform: none !important; - -moz-transform: none !important; - -ms-transform: none !important; - -webkit-transform: none !important; - transform: none !important; - /*CSS animations*/ - -webkit-animation: none !important; - -moz-animation: none !important; - -o-animation: none !important; - -ms-animation: none !important; - animation: none !important; - /*CSS box-shadow*/ - -webkit-box-shadow: none !important; - -moz-box-shadow: none !important; - box-shadow: none !important; } - -select, textarea { - outline: 0; - opacity: 1; - /*CSS transitions*/ - -o-transition-property: none !important; - -moz-transition-property: none !important; - -ms-transition-property: none !important; - -webkit-transition-property: none !important; - transition-property: none !important; - /*CSS transforms*/ - -o-transform: none !important; - -moz-transform: none !important; - -ms-transform: none !important; - -webkit-transform: none !important; - transform: none !important; - /*CSS animations*/ - -webkit-animation: none !important; - -moz-animation: none !important; - -o-animation: none !important; - -ms-animation: none !important; - animation: none !important; - /*CSS box-shadow*/ - -webkit-box-shadow: none !important; - -moz-box-shadow: none !important; - box-shadow: none !important; } - -input[type="text"]:focus, input[type="password"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="week"]:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="color"]:focus, input:focus { - outline: 0; - opacity: 1; - /*CSS transitions*/ - -o-transition-property: none !important; - -moz-transition-property: none !important; - -ms-transition-property: none !important; - -webkit-transition-property: none !important; - transition-property: none !important; - /*CSS transforms*/ - -o-transform: none !important; - -moz-transform: none !important; - -ms-transform: none !important; - -webkit-transform: none !important; - transform: none !important; - /*CSS animations*/ - -webkit-animation: none !important; - -moz-animation: none !important; - -o-animation: none !important; - -ms-animation: none !important; - animation: none !important; - /*CSS box-shadow*/ - -webkit-box-shadow: none !important; - -moz-box-shadow: none !important; - box-shadow: none !important; } - -select:focus, textarea:focus { - outline: 0; - opacity: 1; - /*CSS transitions*/ - -o-transition-property: none !important; - -moz-transition-property: none !important; - -ms-transition-property: none !important; - -webkit-transition-property: none !important; - transition-property: none !important; - /*CSS transforms*/ - -o-transform: none !important; - -moz-transform: none !important; - -ms-transform: none !important; - -webkit-transform: none !important; - transform: none !important; - /*CSS animations*/ - -webkit-animation: none !important; - -moz-animation: none !important; - -o-animation: none !important; - -ms-animation: none !important; - animation: none !important; - /*CSS box-shadow*/ - -webkit-box-shadow: none !important; - -moz-box-shadow: none !important; - box-shadow: none !important; } - -input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill, input:-webkit-autofill:focus, textarea:-webkit-autofill:focus, select:-webkit-autofill:focus { - -webkit-box-shadow: 0 0 0px 1000px white inset; } - -/* Turn Off Number Input Spinners */ -input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; } - -.backup input[type="text"] { - border-bottom: 1px solid #CAD4DB; } - .backup input[type="text"]:focus { - border-bottom: 1px solid #A5B2BF; } - -.label { - font-weight: 500; - padding: 0.3rem 0.4rem; - vertical-align: text-bottom; } - .label.outline { - background: transparent; - border: 1px solid #4B6178; } - .label.outline.gray { - font-size: 90%; - background: transparent; - border: 1px solid #A9B6C2; } - .label.success { - background-color: #1ABC9C; } - .label.alert { - background-color: #ED4A43; } - .label.gray { - background-color: #4B6178; } - -label.postfix { - height: 34px; - border: none; - font-weight: 700; - font-size: 14px; - color: #7A8C9E; - text-transform: uppercase; - position: absolute; - top: 0; - right: 0; - width: 50px; - padding-top: 7px; } - -.input { - position: relative; } - .input.block i { - position: absolute; - top: 2px; - left: 15px; - font-size: 20px; - color: #7A8C9E; - border-right: 1px solid #ccc; - padding-right: 8px; - border-right: 1px solid #E5E8EB; - display: block; - cursor: pointer; } - .input label { - line-height: 0; - padding: 0; } - -.label { - font-size: 70%; - padding: 0.2rem 0.2rem; } - -.settings fieldset { - border: 1px solid #425467; } - .settings fieldset legend { - background: transparent; - color: #A5B2BF; } - -.settings label { - color: #A5B2BF; - font-weight: normal; } - -.bottombar-item a { - color: #A5B2BF; - padding: 0.5rem 0; - display: block; } - .bottombar-item a.active .label { - text-shadow: none; } - -::-webkit-input-placeholder { - color: #B7C2CD; } - -:-moz-placeholder { - /* Firefox 18- */ - color: #B7C2CD; } - -::-moz-placeholder { - /* Firefox 19+ */ - color: #B7C2CD; } - -:-ms-input-placeholder { - color: #B7C2CD; } - -/* - * - * Copay main CSS - * - */ -body { - font-family: Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif; } - -.panel h1, .panel h2, .panel h3, .panel h4, .panel h5, .panel h6, .panel p, .panel li, .panel dl { - color: #2C3E50; } - -#qr-canvas { - display: none; } - -#qrcode-scanner-video { - display: block; - margin: 0 auto; } - -.qr-scanner-input { - position: absolute; - top: 5px; - right: 0; } - -.qr-scanner-input-import { - position: absolute; - top: -5px; - right: 0; } - -.icon-close-import { - padding: 0px 40px 5px 10px; } - -h1, h2, h3, h4, h5, h6 { - color: #2C3E50; } - -h1 { - font-weight: 100; - font-size: 24px; } - -h2 { - font-size: 20px; - font-weight: 100; } - -h3 { - font-weight: 300; - font-size: 16px; } - -h4 { - font-size: 0.875rem; } - -.send h4.title, .glidera h4.title { - border-bottom: 1px solid #E2E7ED; - background: #fff; - padding: 0.8rem; - color: #4B6178; - font-weight: 500; - font-size: 0.75rem; - text-align: center; - line-height: 1.5; } - -h4.title a { - text-transform: none; - font-weight: 400; - font-size: 12px; } - -.preferences form { - background: white; - padding-top: 10px; - margin-bottom: 10px; } - -.preferences .switch { - top: -5px !important; } - -.preferences h4 { - background: #F6F7F9; - padding: 25px 0px 5px 10px; - text-transform: uppercase; - color: #555; - font-size: 12px; - font-weight: 300; - margin: 0; } - -.modal-content h4, .glidera h4, .coinbase h4 { - background: #F6F7F9; - padding: 25px 0px 5px 10px; - text-transform: uppercase; - color: #555; - font-size: 12px; - font-weight: 300; - margin: 0; } - -.walletHome h4.title { - padding: 0px 0 10px 15px; - margin: 5px 0 5px 0; - font-size: 16px; } - -.preferences ul, .modal-content ul { - font-size: 14px; - background: white; } - -.preferences ul li { - padding: 16px 10px 16px 16px; - border-bottom: 1px solid #E9E9EC; } - -.addressbook-input, .disabled-input { - display: block; - margin-bottom: 1.5rem; - background-color: #E4E8EC; - padding-left: 0.5rem; - color: #2C3E50; - font-size: 13px; - height: 35px; - padding-top: 7px; } - -ul.button-group { - margin-top: 8px; } - ul.button-group li:first-child { - border-top-left-radius: 0.2rem; - border-bottom-left-radius: 0.2rem; - border: 1px solid #DEDFE1; } - ul.button-group li:last-child { - border-top-right-radius: 0.2rem; - border-bottom-right-radius: 0.2rem; - border: 1px solid #DEDFE1; } - -.button-group.even-2 li { - margin: 0 -3px; - padding: 4px 5px; } - -ul.button-group li { - color: #A5B2BF; - cursor: pointer; - text-transform: uppercase; - font-size: 0.7rem; - display: block; - padding: 3px 0; } - ul.button-group li.selected { - color: #fff; - background-color: #DEDFE1; } - -body, html { - height: 100%; - width: 100%; - color: #2C3E50; - -webkit-user-select: text; } - -.alt-currency { - padding: 0.05rem 0.2rem; - border-radius: 2px; - font-size: 10px; - color: #fff; - font-weight: 700; } - -.color-greeni { - color: #1abc9c !important; } - -.color-yellowi { - color: yellow !important; } - -.color-alert { - color: #ED4A43; } - -.alt-currency.green { - background: #1abc9c; } - -.alt-currency.red { - background: #A02F23; } - -.alt-currency.black { - background: #213140; } - -.alt-currency.gray { - background: #7A8C9E; } - -a { - color: #3498DB; } - -.sub-header { - background: #F1f3F5; - padding: 0.8rem; - overflow: hidden; } - -.status { - color: #FFFFFF; - background-color: #A02F23; - position: absolute; - left: 250px; - right: 0; - bottom: 0; - padding: 10px 1rem 10px 0.5rem; - z-index: 9; - font-size: 14px; - text-align: left; - line-height: 17px; } - -.status-first-line { - z-index: 9; - font-size: 16px; } - -.main-dark { - background-color: #2C3E50; - height: 100%; } - -.page, .main { - height: 100%; - background-color: #F6F7F9; } - -.waiting { - border: 2px solid #fff; } - -.online { - border: 2px solid #1ABC9C; } - -.main { - background-color: #F6F7F9; - padding: 0 0 58px 0; - position: relative; } - -.half-row { - width: 50%; - padding: 5px; } - -.content { - width: 100%; - position: absolute; - top: 45px; - bottom: 0; - overflow: auto; } - .content.disclaimer { - top: 0; } - -.box-setup-footer { - overflow: hidden; - margin-top: 1rem; - padding: 1rem 0 0; - border-top: 1px solid #425467; - font-size: 12px; } - -.box-notification { - position: relative; - font-size: 12px; - padding: 0.5rem; - border-radius: 2px; - background: #FFFFFF; } - .box-notification .box-icon { - position: absolute; - top: 0; - left: 0; - color: white; - background-color: #1ABC9C; - padding: 0 0.5rem; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; - height: 100%; } - .box-notification .box-icon i { - position: relative; - top: 10%; - display: block; } - .box-notification .box-icon.error { - background-color: #ED4A43; } - .box-notification .box-icon.secondary { - background-color: #3498DB; } - -a.close-notification { - position: absolute; - top: -4px; - right: 10px; - font-size: 24px; } - -ul.tx-copayers { - background: #E4E8EC; - padding: 0.3rem 0.8rem; - margin-left: 0; - box-shadow: inset 0 1px 1px 0 rgba(10, 19, 28, 0.12); - border-radius: 0 0 3px 3px; } - -.tx-copayers li { - list-style: none; - padding: 0.3rem; - font-size: 12px; } - .tx-copayers li.bottom-line-copayers { - border-bottom: 1px solid #CAD2DA; } - -.last-transactions-content { - background: #fff; - padding: 0.8rem 1rem; - cursor: pointer; - border-bottom: 1px solid #E4E8EC; } - -.sign-action { - background: #E4E8EC; - width: 100%; - padding: 1rem; - text-align: center; } - -.icon-circle-active { - position: absolute; - bottom: 2px; - right: 2px; } - -.icon-sign { - padding: 0.2rem 0.3rem; - border-radius: 100%; - color: #fff; - font-size: 10px; - margin-top: 3px; } - .icon-sign.check { - background-color: #3FBC9C; } - .icon-sign.x { - background-color: #C0392B; } - -.circle-icon { - background: #fff; - border-radius: 100%; - padding: 1.5rem; - width: 80px; - height: 80px; - margin: 0 auto; } - -.receive .circle-icon, .backup .circle-icon { - padding: 0.2rem; - margin-bottom: 2rem; } - -.receive h5, .backup h5 { - font-weight: 500; - color: #4B6178; - margin-bottom: 1rem; } - -.receive p { - font-size: 0.9rem; - margin-bottom: 2rem; } - -.backup p { - font-size: 0.9rem; - margin-bottom: 2rem; } - -.backup .tab-bar { - background: #F6F7F9; - border-bottom: none; } - -.extra-padding-bottom { - padding-bottom: 78px; } - -.date-message { - background-color: #213140; - border-radius: 3px; - font-size: 12px; - padding: 0.2rem 0.4rem; - color: #7A8C9E; } - -.input-note { - margin-top: -10px; - display: block; - margin-bottom: 1rem; } - -.send-note { - background-color: #F8F8FB; - padding: 10px; } - .send-note span { - margin-bottom: 5px; - font-size: 12px; - color: #2C3E50; } - -.manage a { - text-transform: uppercase; - font-weight: 700; - color: #4B6178; - padding: 1.5rem 1rem; - display: block; - overflow: hidden; } - .manage a span { - display: block; - margin-top: 8px; - float: left; } - -ul.manage li { - border-bottom: 1px solid #f1f3f5; } - -.manage a i.circle { - background-color: #4B6178; - width: 50px; - height: 50px; - padding: 0.65rem; - border-radius: 100%; - display: block; - font-size: 30px; - color: #fff; - float: left; - margin-right: 20px; } - .manage a i.circle.plus-fixed { - padding: 0.1rem 0.9rem; } - -.dn { - display: none; } - -.dni { - display: none !important; } - -.pr { - position: relative; } - -.pa { - position: absolute; } - -.m0 { - margin: 0; } - -.p0i { - padding: 0 !important; } - -.db { - display: block; } - -.dib { - display: inline-block; } - -.size-10 { - font-size: 10px; } - -.size-12 { - font-size: 12px; } - -.size-14 { - font-size: 14px; } - -.size-16 { - font-size: 16px; } - -.size-18 { - font-size: 18px; } - -.size-21 { - font-size: 21px; } - -.size-24 { - font-size: 24px; } - -.size-36 { - font-size: 36px; } - -.size-42 { - font-size: 42px; } - -.size-48 { - font-size: 48px; } - -.size-60 { - font-size: 60px; } - -.size-72 { - font-size: 72px; } - -.m5 { - margin: 5px; } - -.m5t { - margin-top: 5px; } - -.m8t { - margin-top: 8px; } - -.m5b { - margin-bottom: 5px; } - -.m5r { - margin-right: 5px; } - -.m10 { - margin: 10px; } - -.m10b { - margin-bottom: 10px; } - -.m10t { - margin-top: 10px; } - -.m15b { - margin-bottom: 15px; } - -.m15r { - margin-right: 15px; } - -.m20b { - margin-bottom: 20px; } - -.m30b { - margin-bottom: 30px; } - -.m40b { - margin-bottom: 40px; } - -.m50b { - margin-bottom: 50px; } - -.m10r { - margin-right: 10px; } - -.m40r { - margin-right: 40px; } - -.m25r { - margin-right: 25px; } - -.m10l { - margin-left: 10px; } - -.m5l { - margin-left: 5px; } - -.m15l { - margin-left: 15px; } - -.m15t { - margin-top: 15px; } - -.m20r { - margin-right: 20px; } - -.m20t { - margin-top: 20px; } - -.m20ti { - margin-top: 20px !important; } - -.m20tp { - margin-top: 20%; } - -.m30tp { - margin-top: 30%; } - -.m15 { - margin: 15px; } - -.m15h { - margin: 0 15px; } - -.p10t { - padding-top: 10px; } - -.p10h { - padding-right: 10px; - padding-left: 10px; } - -.p0r { - padding-right: 0; } - -.p70r { - padding-right: 70px; } - -.p70l { - padding-left: 70px; } - -.p5h { - padding: 0 5px; } - -.p20h { - padding: 0 20px; } - -.p20v { - padding: 20px 0; } - -.p20b { - padding-bottom: 20px; } - -.p25b { - padding-bottom: 25px; } - -.p25l { - padding-left: 25px; } - -.p15l { - padding-left: 15px; } - -.p15 { - padding: 15px; } - -.p20 { - padding: 20px; } - -.p20t { - padding-top: 20px; } - -.p50t { - padding-top: 50px; } - -.p10 { - padding: 10px; } - -.p10i { - padding: 10px !important; } - -.p10b { - padding-bottom: 10px; } - -.p45t { - padding-top: 45px; } - -.p60t { - padding-top: 60px; } - -.p60b { - padding-bottom: 60px; } - -.m60t { - margin-top: 60px; } - -.p45li { - padding-left: 45px !important; } - -.m30v { - margin: 30px 0; } - -.m10h { - margin: 0 10px; } - -.m10v { - margin: 10px 0; } - -.m20v { - margin: 20px 0; } - -.m30a { - margin: 30px auto; } - -.m-negative-l { - margin-left: -0.9375rem; } - -.br100 { - border-radius: 100% !important; } - -.lh { - line-height: 0; } - -.lh140 { - line-height: 140%; } - -.oh { - overflow: hidden; } - -.vm { - vertical-align: middle; } - -.vt { - vertical-align: top; } - -.ma { - margin: 0 auto; } - -.tu { - text-transform: uppercase; } - -.tl { - text-transform: lowercase; } - -.line { - border-top: 1px solid #F8F8FB; - margin: 0.7rem 0; } - -.line-white { - border-top: 1px solid #fff; - margin: 0.7rem 0; } - -.line-t { - border-top: 1px solid #E9E9EC; } - -.line-b { - border-bottom: 1px solid #E9E9EC; } - -.name-wallet { - font-size: 14px; - font-weight: 400; - padding-top: 0 !important; - line-height: 14px; } - -.release { - cursor: pointer; - cursor: hand; - background-color: #E9E9EC; - margin-top: -30px; - margin-bottom: 5px; - padding-top: 30px; - padding-bottom: 20px; - text-align: center; - text-color: #444; } - .release span { - margin-left: 15px; } - .release i { - margin-right: 15px; } - -.tab-bar h1, .tab-bar h2, .tab-bar h3, .tab-bar h4, .tab-bar h5, .tab-bar h6 { - line-height: 48px; } - -.locked { - font-size: 11px; - color: #7A8C9E; } - -.hidden { - visibility: hidden; } - -.spinner { - display: inline-block; } - -.success { - color: #1ABC9C; } - -.bg-success { - background-color: #1ABC9C; } - -.lock-fromQR { - position: absolute; - width: 100%; - margin-top: 20px; } - -.tx-proposal i { - padding: .1rem .3rem; - background-color: #A5B2BF; - border-radius: 100%; - color: #fff; } - .tx-proposal i.active { - background-color: #A02F23; } - -.header-modal { - background: #fff; - width: 100%; - padding-top: 20px; - padding-bottom: 20px; - position: relative; } - -.bg-alert { - background-color: #ED4A43; } - -.ellipsis { - display: block; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; } - -ul.pagination li.current a { - background: #1ABC9C; } - -table { - border-collapse: collapse; - text-align: left; - width: 100%; - border: none; } - -thead tr { - text-transform: uppercase; } - -table tr td, table tr th { - padding: 15px; } - -table tr.even, table tr.alt, table tr:nth-of-type(even) { - background: #fff; } - -table tfoot tr td, table tfoot tr th { - background-color: #F5F5F8; - color: #949BAD; - font-weight: normal; } - -table thead tr td, table thead tr th { - background-color: #F5F5F8; - color: #949BAD; - font-weight: normal; } - -table tbody td { - color: #7A8C9E; - border-bottom: 1px solid #F1F1F3; } - -table tbody tr:last-child td { - border-bottom: none; } - -.wallet-selection.wallets { - background-color: #213140; } - -ul.wallet-selection.wallets { - margin: 0; - overflow: hidden; } - -.wallet-selection.wallets li { - overflow: hidden; - padding: 1rem; } - .wallet-selection.wallets li a { - display: block; } - -.pointer { - cursor: pointer; } - -.icon-wallet { - display: block; } - -.walletHome .icon-wallet { - display: inline-block; - margin: 0; - vertical-align: baseline; } - -.icon-input { - font-size: 9px; - color: #fff; - vertical-align: middle; - margin-right: 3px; } - .icon-input .fi-check { - padding: .2rem .3rem; - background-color: #1ABC9C; - border-radius: 100%; - display: block; } - .icon-input .fi-x { - padding: .1rem .3rem; - background-color: #ED4A43; - border-radius: 100%; } - -.has-error { - color: #ED4A43; } - -.is-valid { - color: #1ABC9C; } - -input.ng-invalid-match { - border-color: red; } - input.ng-invalid-match:focus { - border-color: red; } - -.black { - background-color: #2C3E50; } - -.white { - background-color: #FFFFFF; } - -.text-italic { - font-style: italic; } - -.text-light { - font-weight: 200; } - -.text-bold { - font-weight: 700; } - -.text-gray { - color: #8597A7; } - -.text-black { - color: #2C3E50; } - -.text-primary { - color: #1ABC9C; } - -.text-secondary { - color: #3498DB; } - -.text-white { - color: #fff; } - -.text-warning { - color: #ED4A43; } - -.text-alert { - color: red; } - -.text-success { - color: #1ABC9C; } - -.text-spacing { - letter-spacing: 2px; } - -.text-capitalize { - text-transform: capitalize; } - -.text-shadow { - text-shadow: 2px 2px 3px #969696; } - -.payment-uri .panel { - line-height: 1.4; } - -.panel { - background: #FFFFFF; - border-radius: 3px; - padding: 1rem; } - .panel.words { - background: #E6EAEE; - border: 1px dashed #A5B2BF; - min-height: 147px; } - -.panel qrcode { - background-color: white; } - .panel qrcode canvas { - width: 250px; - height: 250px; } - -.tour { - text-align: center; - height: 100%; } - -.tour5 { - width: 90%; - position: absolute; - bottom: 10%; - margin: 0 auto; - margin-left: 5%; } - -.secret { - overflow-wrap: break-word; - word-wrap: break-word; - text-align: center; - font-size: 14px; - margin: 10px; } - -.collapse { - margin: auto; - max-width: 100%; } - -.w-popup-menu { - padding: 0; } - .w-popup-menu li { - width: 180px; - height: 180px; - overflow: hidden; - position: relative; - float: left; - background: #213140; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - -webkit-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); - box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2); - margin: 20px 26px 0 0; } - .w-popup-menu li:last-child { - margin-right: 0px; } - .w-popup-menu li a { - text-align: center; - width: 100%; - height: 100%; - display: block; - color: #333; - position: relative; } - -.w-popup-icon { - color: #c5e4f4; - font-size: 90px; - text-shadow: 1px 0 1px rgba(255, 255, 255, 0.7); - line-height: 150px; - position: absolute; - width: 58px; - left: 60px; - top: 14px; - text-align: center; } - -.w-popup-content { - position: absolute; - left: 0px; - width: 100%; - height: 50%; - top: 50%; } - -.w-popup-main { - color: #FFFFFF; - opacity: 0.6; - text-align: center; - margin-bottom: 5px; } - -.w-popup-sub { - text-align: center; - color: #FFFFFF; - line-height: 20px; - opacity: 0.8; } - -/*///////////////////////// LOADING /////////////////////////*/ -.loading-screen { - width: 100%; - height: 100%; - position: absolute; - z-index: 999; - top: 0; - left: 0; - background-color: #2C3E50; } - -.loading-screen-content { - margin-top: 20%; - width: 100%; - text-align: center; } - -/*/////////////////////////////////////////////////*/ -.terms { - padding: 0.8rem; } - .terms ul { - font-size: 0.8rem; - text-align: justify; - margin-left: 0; } - .terms li { - list-style-type: none; - display: inline; } - -.scrollArea { - height: 280px; - overflow: scroll; - background: #213140; - border: 1px solid #4B6178; - border-radius: 5px; - margin: 1rem; - color: #A5B2BF; - line-height: 30px; - padding: 0.5rem; } - .scrollArea ul { - font-size: 0.8rem; - text-align: left; - margin-left: 0; - line-height: 1.4; - margin-bottom: 0; } - .scrollArea li { - list-style-type: none; - display: inline; } - -.tabbable { - border: 2px solid #213140; - border-radius: 3px; - margin-bottom: 1.2rem; } - -.tabs dd.active a { - color: #fff; - background-color: transparent; } - -.tabs dd > a { - background: #213140; - text-transform: uppercase; - color: #3E4F5D; - padding: 1rem; - text-align: center; - height: 64px; - font-size: 14px; - line-height: 15px; } - -.tabs-content { - margin-bottom: 0; } - .tabs-content > .content { - padding: 0; } - -.content-item { - border-bottom: 1px solid rgba(32, 48, 64, 0.3); - box-shadow: 0px 1px 0px 0px rgba(121, 140, 158, 0.1); - margin: .5rem 1.3rem; - padding: 0.3rem 0; - font-size: 14px; } - -.bg-gray { - background-color: #F1F3F5; } - -.bg-circle { - background: #253547; - border-radius: 100%; - margin: 0 0.5rem 0.3rem 0; - padding: .45rem 0.5rem; - display: inline-block; - text-align: center; - vertical-align: middle; - color: #7A8C9E; - font-size: 30px; - width: 50px; - height: 50px; } - -.session-expired { - background: rgba(32, 48, 64, 0.9); - width: 100%; - height: 100%; - position: absolute; - color: #fff; - z-index: 999; - padding-top: 20%; - text-align: center; - padding-left: 10%; - padding-right: 10%; } - -.line-none { - border: none; - box-shadow: none; } - -.splash { - top: 0; - background: #2C3E50; - background-image: -webkit-linear-gradient(#3D5672 0%, #223243 100%); - background-image: -o-linear-gradient(#3D5672 0%, #223243 100%); - background-image: linear-gradient(#3D5672 0%, #223243 100%); } - .splash .start-button button.black { - background-color: #4B6178; } - .splash .start-button button.outline.tiny { - font-size: 0.58rem; } - .splash .container-image { - padding: 1rem 0; } - -.preferences li { - cursor: pointer !important; } - -.preferences-icon { - width: auto; - height: 40px; } - -@media only screen and (max-width: 40em) { - .preferences-icon { - width: 40px; - height: 40px; - padding: 0.55rem !important; } } - -.tx-details-blockchain li { - cursor: pointer !important; } - -.onGoingProcess { - left: 0; - width: 100%; - bottom: 90px; - position: absolute; - z-index: 1020; } - -.onGoingProcess-content { - background: #213140; - text-align: center; - max-width: 16.5rem; - max-height: 3.5rem; - margin: auto; - color: #fff; - padding: 0.5rem; - font-size: 13px; - opacity: 0.8; - border-radius: 3px; } - -/*/////////////////// SPINNER ////////////////////*/ -#history .spinner, #receive .spinner, .copayers .spinner { - height: 46px; } - -#history .spinner > div, #receive .spinner > div, .copayers .spinner > div, .preferences-fee .spinner > div { - background-color: #7A8C9E; } - -.spinner { - margin: 0 auto; - width: 35px; - height: 27px; - text-align: center; - font-size: 10px; - vertical-align: middle; } - -.walletHome .spinner > div { - background-color: #8597A7; } - -.spinner > div { - background-color: #fff; - height: 100%; - width: 2px; - display: inline-block; - -webkit-animation: stretchdelay 1.2s infinite ease-in-out; - animation: stretchdelay 1.2s infinite ease-in-out; } - -.spinner .rect2 { - -webkit-animation-delay: -1.1s; - animation-delay: -1.1s; } - -.spinner .rect3 { - -webkit-animation-delay: -1.0s; - animation-delay: -1.0s; } - -.spinner .rect4 { - -webkit-animation-delay: -0.9s; - animation-delay: -0.9s; } - -.spinner .rect5 { - -webkit-animation-delay: -0.8s; - animation-delay: -0.8s; } - -.tab-bar { - background-color: #4B6178; - z-index: 5; } - .tab-bar h1 { - font-weight: 500; - font-size: 14px; } - -.tab-bar-section.middle { - left: 4.7rem; - right: 4.7rem; } - -.left-small { - width: 4.7rem; - line-height: 2.95rem; - border-right: none; } - -.right-small { - width: 4.7rem; - text-align: right; - line-height: 2.7rem; - border-left: none; } - .right-small a { - color: #FFFFFF; } - -.left-small a { - color: #FFFFFF; } - -.backup .right-small a, .backup .left-small a { - color: #7A8C9E; } - -.tab-bar .icon-back { - font-size: 2.5rem; - position: absolute; - line-height: 52px; - left: -5px; - height: 45px; - top: 0px; } - -.tab-bar .text-back { - margin-left: 26px; - font-size: 0.9rem; - font-weight: 400; - padding: 10px 0; - visibility: middle; } - -.tab-bar .text-close { - font-size: 0.9rem; - font-weight: 400; - line-height: 2.95rem; } - -.bottom-bar { - display: block; - position: fixed; - bottom: 0; - width: 100%; - z-index: 5; - background: #FFFFFF; - border-top: 1px solid #E2E7ED; } - -.second-bottom-bar { - z-index: 6; } - .second-bottom-bar.animated.slideInRight, .second-bottom-bar.animated.slideInLeft { - -webkit-animation-duration: 0.3s; - animation-duration: 0.3s; } - -.menu-toggle { - padding-top: 1rem !important; } - -.menu-wallet-home { - background: #fff linear-gradient(-180deg, #F1F3F5 0%, #FFFFFF 30%); - box-shadow: 0px -1px 0px 0px rgba(165, 178, 191, 0.35); - width: 100%; - height: 8rem; - position: absolute; - top: -10px; - margin-left: auto; - margin-right: auto; - left: 0; - right: 0; - border-radius: 100%; - z-index: -999; } - -.amount { - width: 100%; - text-align: center; - padding: 1.5rem 1rem 1.5rem 1rem; - color: #fff; - height: 150px; - margin-bottom: 25px; } - -.alternative-amount { - height: 25px; - text-align: center; } - -.scroll-section { - position: absolute; - top: 120px; - overflow-y: auto; } - -.status { - bottom: 65px; - left: 0; } - -.walletHome .avatar-wallet { - padding: 0.5rem; - width: 75px; - height: 75px; - position: absolute; - top: -22px; - font-size: 2.2rem; - border: 3px solid #fff; - background: #1ABC9C; - margin: 0; - color: #FFF; - font-weight: 700; - text-align: center; - border-radius: 5px; } - -.walletHome .wallet-info { - position: absolute; - top: inherit; - left: 10px; - bottom: 26px; - font-size: 20px; - color: #fff; } - -.camera-icon a { - background: #4B6178; - box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5); - color: #fff; - display: block; - position: absolute; - padding: 15px 17px; - border-radius: 100%; - top: inherit; - right: 15px; - bottom: 2px; - line-height: 12px; } - -.send .camera-icon a { - top: inherit; - bottom: 0; } - -ul.copayer-list img { - width: 30px; - height: 30px; } - -.box-founds { - background-color: #213140; } - -a.missing-copayers { - bottom: -34px; - text-align: center; - padding: .7rem; - width: 100%; } - -.box-setup, .footer-setup { - margin-bottom: 50px; } - -.sidebar ion-content { - background: #2C3E50; - top: 115px; } - -.sidebar { - background: #2C3E50; } - .sidebar .icon { - width: 39px; - text-align: center; - margin-right: 15px; - float: left; - display: block; } - -.modal-content .icon { - width: 39px; - text-align: center; - margin-right: 15px; - float: left; - display: block; } - -.sidebar li { - overflow: hidden; - border-bottom: 1px solid #384B5F; } - .sidebar li.nav-item.selected { - background-color: #122232; } - -.sidebar .avatar-wallet { - background-color: #2C3E50; - color: #fff; - font-size: 1.4rem; - font-weight: 700; - margin-right: 15px; - text-align: center; - float: left; - width: 35px; - height: 30px; - border-radius: 3px; - padding-top: 4px; } - -.payment-uri .avatar-wallet, .modal-content .avatar-wallet { - background-color: #2C3E50; - color: #fff; - font-size: 1.4rem; - font-weight: 700; - margin-right: 15px; - text-align: center; - float: left; - width: 35px; - height: 30px; - border-radius: 3px; - padding-top: 5px; } - -.sidebar header { - text-align: center; - padding: 1.7rem; - border-bottom: 1px solid #384B5F; } - .sidebar header h1 { - color: #fff; - margin: 0; - padding: 5px; } - .sidebar header small { - color: #fff; } - -.sidebar li { - overflow: hidden; - border-bottom-style: solid; - border-bottom-width: 1px; - padding: 1rem 0.7rem; - font-size: 12px; - font-weight: 300; - color: #A5B2BF; - cursor: pointer !important; } - -.sidebar ul { - margin: 0 0 30px 0; } - -.modal-content ul li a { - font-size: 12px; - font-weight: 300; - border-bottom: transparent; - color: #A5B2BF; - padding: 1rem 0.7rem; } - .modal-content ul li a.removeAddressbook { - background-color: white; - color: red; - margin-right: -10px; - float: right; } - .modal-content ul li a.selectAddressbook { - float: left; - font-size: 18px; - padding: 13px 14px; - color: red; - margin-right: 10px; } - -/* - * Remove all vendors hover / shadow / fade - */ -.tooltip { - display: none !important; } - -.move-right .exit-off-canvas, .move-left .exit-off-canvas { - box-shadow: none; } - -/* === */ -/* Have to set height explicity on ui-view -to prevent collapsing during animation*/ -.main[ui-view] { - height: 100%; - /* TODO */ } - -.ui-view-container { - position: relative; - height: 100%; } - -[ui-view].slideDown, [ui-view].slideRight, [ui-view].slideLeft { - z-index: 100; } - -#mainSection, #mainSectionDup { - height: 100%; - position: absolute; - left: 0; - right: 0; - animation-timing-function: ease-in-out; - animation-duration: .3s; - animation-iteration-count: 1; - animation-fill-mode: both; - -webkit-animation-timing-function: ease-in-out; - -webkit-animation-duration: .3s; - -webkit-animation-iteration-count: 1; - -webkit-animation-fill-mode: both; } - -.CslideInUp { - -webkit-animation-name: slideInUp; - animation-name: slideInUp; - z-index: 1003; } - -.CslideOutDown { - -webkit-animation-name: slideOutDown; - animation-name: slideOutDown; - z-index: 1003; } - -.CslideOutRight { - -webkit-animation-name: slideOutRight; - animation-name: slideOutRight; - z-index: 1003; } - -.CslideInRight { - -webkit-animation-name: slideInRight; - animation-name: slideInRight; - z-index: 1003; } - -/* == */ -.icon-circle, .icon-circle-active { - color: #1ABC9C; } - -.tx-comment { - border-top: 1px solid #eee; - padding-top: 10px; - margin-top: 10px; } - -/* notifications */ -.dr-notification-container { - position: absolute; - z-index: 10000; - width: 100%; } - .dr-notification-container.bottom { - bottom: 20px; } - .dr-notification-container.right { - right: 0; } - .dr-notification-container.left { - left: 20px; } - .dr-notification-container.top { - top: 45px; } - .dr-notification-container.center { - left: 50%; - margin-left: -190px; } - -.dr-notification-wrapper { - position: relative; - width: 100%; - margin: 0; } - .dr-notification-wrapper.offline { - position: absolute; - top: 0px; - z-index: 2000; - opacity: 1.0 !important; - background-color: #2C3E50; } - .dr-notification-wrapper.client-error { - position: absolute; - top: 45px; - z-index: 11; } - -.dr-notification-close-btn { - color: #A5B2BF; - border: 1px solid #A5B2BF; - border-radius: 100%; - display: inline-block; - padding: 0px 8px; - position: absolute; - right: 5px; - cursor: pointer; - z-index: 10; - margin: 14px 8px 0; - font-size: 20px; } - -.dr-notification-image { - float: left; - color: #fff; - text-align: center; - background-color: #213140; - width: 40px; - height: 40px; - font-size: 1.5rem; - border-radius: 100%; - margin: 0.6rem; } - .dr-notification-image img { - margin: 15px; - max-width: 70px; - min-width: 48px; } - -.dr-notification-content { - line-height: 90%; - padding: 10px 50px 5px 60px; } - -.dr-notification-title { - color: #fff; - font-size: 12px; - margin-bottom: 0; - font-weight: 700; } - -.dr-notification { - background: rgba(44, 62, 80, 0.9); - box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.2); - width: 100%; - clear: both; - overflow: hidden; - border-radius: 0; - height: 60px; } - -.dr-notification-text { - font-size: 11px; - color: #fff; } - -/*** modals ***/ -.hideModal { - visibility: none !important; - display: none !important; } - -.reveal-modal-bg { - display: none !important; } - -.reveal-modal.full { - top: 0 !important; } - -.modal-content { - position: relative; - height: 100%; - width: 100%; - -webkit-transform: translate3d(0, 0, 0); - background: #f6f7f9; } - -body.modal-open { - position: fixed; - overflow: hidden; - z-index: 1; } - -.reveal-modal { - padding: 0; - border: none; - border-radius: 0; - outline: 0; - box-shadow: none; } - .reveal-modal.animated.slideInRight, .reveal-modal.animated.slideOutRight { - -webkit-animation-duration: 0.3s; - animation-duration: 0.3s; } - -.reveal-modal.animated.fadeOutUp, .reveal-modal.animated.slideInUp, .reveal-modal.animated.slideInDown { - -webkit-animation-duration: 0.3s; - animation-duration: 0.3s; } - -.popup-tx-status { - z-index: 1030; } - -.popup-txsent { - position: absolute; - width: 100%; - height: 100%; - background: rgba(24, 44, 58, 0.9); } - .popup-txsent i { - font-size: 5rem; - color: #4A90E2; - border-radius: 100%; - border-color: #4A90E2; - border: 2px solid; - width: 150px; - height: 150px; - display: block; - text-align: center; - padding-top: 1rem; } - -.popup-txsigned i, .popup-txrejected i { - font-size: 5rem; - color: #4A90E2; - border-radius: 100%; - border-color: #4A90E2; - border: 2px solid; - width: 150px; - height: 150px; - display: block; - text-align: center; - padding-top: 1rem; } - -.payment-proposal-head { - color: #fff; - padding: 10px 10px 20px 10px; - text-align: center; } - -.payment-proposal-to { - width: 100%; - display: inline-block; - padding: 5px 15px; - background-color: rgba(0, 0, 0, 0.1); } - .payment-proposal-to i { - position: inherit; - left: 25px; - padding-right: 10px; - border-right: 1px solid; - border-color: rgba(255, 255, 255, 0.1); - font-size: 20px; } - -.tab-view { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - width: 100%; - position: absolute; - top: 44px; - bottom: 37px; - overflow: auto; - padding-bottom: 40px; } - -.tab-in { - -webkit-transform: translate3d(0, 0, 0) !important; - transform: translate3d(0, 0, 0) !important; } - -.tab-out { - -webkit-transform: translate3d(-100%, 0, 0) !important; - transform: translate3d(-100%, 0, 0) !important; } - -.create-tab { - background-color: #fff; - width: 100%; - border-bottom: 1px solid #DEDFE1; - margin-bottom: 25px; - overflow: hidden; } - .create-tab .tab-container { - float: left; - text-align: center; } - -.test { - background: red; } - -.create-tab a { - font-size: .7rem; - padding: 1.2rem .2rem .6rem .2rem; - color: #7A8C9E; - text-transform: uppercase; - font-weight: 500; - display: block; } - -.tab-container.selected { - border-bottom: 3px solid #4B6178; } - .tab-container.selected a { - color: #2C3E50; } - -/*//////////////////////////// SEARCH INPUT ////////////////////////////*/ -.searchBar { - display: table; } - .searchBar .columns { - display: table-cell; - vertical-align: middle; - float: none; } - .searchBar [class*="column"] + [class*="column"]:last-child { - float: none; } - .searchBar form { - margin-left: 20px; } - .searchBar input { - margin-bottom: auto; - border-bottom: 0px solid #E9EDF0; - padding-left: 8px; } - .searchBar i { - position: absolute; - padding: 8px 0 8px 8px; } - .searchBar .small-11 { - padding-right: 5px; - padding-left: 5px; } - .searchBar .small-1 { - padding-left: 2px; - padding-right: 8px; } - -.searchLabel { - margin-top: 10px; - margin-bottom: 10px; - background-color: rgba(0, 0, 0, 0.02); - border-radius: 10px; - position: relative; } - -@font-face { - font-family: 'icomoon'; - src:url("../font/icomoon.eot"); - src:url("../font/icomoon.eot?#iefix") format('embedded-opentype'), - url("../font/icomoon.woff") format('woff'), - url("../font/icomoon.ttf") format('truetype'), - url("../font/icomoon.svg#icomoon") format('svg'); - font-weight: normal; - font-style: normal; -} - -[class^="icon-"], [class*=" icon-"] { - font-family: 'icomoon' !important; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: middle; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.icon-activity-active:before { - content: "\e904"; -} -.icon-receive-active:before { - content: "\e905"; -} -.icon-send-active:before { - content: "\e906"; -} -.icon-wallet:before { - content: "\e903"; -} -.icon-activity:before { - content: "\e900"; -} -.icon-receive:before { - content: "\e901"; -} -.icon-sold .path1:before { - content: "\e631"; - color: rgb(255, 255, 255); -} -.icon-sold .path2:before { - content: "\e632"; - margin-left: -1.0537109375em; - color: rgb(246, 166, 35); -} -.icon-sold .path3:before { - content: "\e633"; - margin-left: -1.0537109375em; - color: rgb(246, 166, 35); -} -.icon-sold .path4:before { - content: "\e634"; - margin-left: -1.0537109375em; - color: rgb(44, 62, 80); -} -.icon-sold .path5:before { - content: "\e635"; - margin-left: -1.0537109375em; - color: rgb(255, 255, 255); -} -.icon-sold .path6:before { - content: "\e636"; - margin-left: -1.0537109375em; - color: rgb(255, 255, 255); -} -.icon-bought .path1:before { - content: "\e637"; - color: rgb(255, 255, 255); -} -.icon-bought .path2:before { - content: "\e638"; - margin-left: -1.0537109375em; - color: rgb(26, 188, 156); -} -.icon-bought .path3:before { - content: "\e639"; - margin-left: -1.0537109375em; - color: rgb(26, 188, 156); -} -.icon-bought .path4:before { - content: "\e63a"; - margin-left: -1.0537109375em; - color: rgb(44, 62, 80); -} -.icon-bought .path5:before { - content: "\e63b"; - margin-left: -1.0537109375em; - color: rgb(255, 255, 255); -} -.icon-bought .path6:before { - content: "\e63c"; - margin-left: -1.0537109375em; - color: rgb(255, 255, 255); -} -.icon-sold-pending:before { - content: "\e63d"; -} -.icon-bought-pending:before { - content: "\e63e"; -} -.icon-sell-bitcoin .path1:before { - content: "\e63f"; - color: rgb(44, 62, 80); -} -.icon-sell-bitcoin .path2:before { - content: "\e640"; - margin-left: -1.2119140625em; - color: rgb(44, 62, 80); -} -.icon-sell-bitcoin .path3:before { - content: "\e641"; - margin-left: -1.2119140625em; - color: rgb(44, 62, 80); -} -.icon-sell-bitcoin .path4:before { - content: "\e642"; - margin-left: -1.2119140625em; - color: rgb(246, 166, 35); -} -.icon-sell-bitcoin .path5:before { - content: "\e643"; - margin-left: -1.2119140625em; - color: rgb(255, 255, 255); -} -.icon-sell-bitcoin .path6:before { - content: "\e644"; - margin-left: -1.2119140625em; - color: rgb(255, 255, 255); -} -.icon-buy-bitcoin .path1:before { - content: "\e645"; - color: rgb(44, 62, 80); -} -.icon-buy-bitcoin .path2:before { - content: "\e646"; - margin-left: -1.2119140625em; - color: rgb(44, 62, 80); -} -.icon-buy-bitcoin .path3:before { - content: "\e647"; - margin-left: -1.2119140625em; - color: rgb(44, 62, 80); -} -.icon-buy-bitcoin .path4:before { - content: "\e648"; - margin-left: -1.2119140625em; - color: rgb(26, 188, 156); -} -.icon-buy-bitcoin .path5:before { - content: "\e649"; - margin-left: -1.2119140625em; - color: rgb(255, 255, 255); -} -.icon-buy-bitcoin .path6:before { - content: "\e64a"; - margin-left: -1.2119140625em; - color: rgb(255, 255, 255); -} -.icon-bank:before { - content: "\e630"; -} -.icon-minus-circle:before { - content: "\e62c"; -} -.icon-plus-circle:before { - content: "\e62d"; -} -.icon-close-circle:before { - content: "\e62e"; -} -.icon-checkmark-circle:before { - content: "\e62b"; -} -.icon-circle:before { - content: "\e629"; -} -.icon-circle-active:before { - content: "\e627"; -} -.icon-send:before { - content: "\e902"; -} -.icon-trash:before { - content: "\e626"; -} -.icon-wallet2:before { - content: "\e622"; -} -.icon-history:before { - content: "\e623"; -} -.icon-reference:before { - content: "\e621"; -} -.icon-bell:before { - content: "\e61c"; -} -.icon-wrench:before { - content: "\e61d"; -} -.icon-download:before { - content: "\e61e"; -} -.icon-upload:before { - content: "\e61f"; -} -.icon-power:before { - content: "\e620"; -} -.icon-forward:before { - content: "\e624"; -} -.icon-compose:before { - content: "\e610"; -} -.icon-contact:before { - content: "\e611"; -} -.icon-email:before { - content: "\e612"; -} -.icon-gear:before { - content: "\e613"; -} -.icon-home:before { - content: "\e614"; -} -.icon-locked:before { - content: "\e615"; -} -.icon-paperplane:before { - content: "\e617"; -} -.icon-people:before { - content: "\e618"; -} -.icon-person:before { - content: "\e619"; -} -.icon-pricetag:before { - content: "\e61a"; -} -.icon-pricetags:before { - content: "\e61b"; -} -.icon-bitcoin:before { - content: "\e60f"; -} -.icon-usd:before { - content: "\e616"; -} -.icon-scan:before { - content: "\e62a"; -} -.icon-scan:before { - content: "\e62a"; -} -.icon-erase:before { - content: "\e628"; -} -.icon-receive2:before { - content: "\e62f"; -} -.icon-arrow-left:before { - content: "\e600"; -} -.icon-arrow-down:before { - content: "\e601"; -} -.icon-arrow-up:before { - content: "\e602"; -} -.icon-arrow-right:before { - content: "\e603"; -} -.icon-arrow-left2:before { - content: "\e604"; -} -.icon-arrow-down2:before { - content: "\e605"; -} -.icon-arrow-up2:before { - content: "\e606"; -} -.icon-arrow-right2:before { - content: "\e607"; -} -.icon-arrow-left3:before { - content: "\e608"; -} -.icon-arrow-down3:before { - content: "\e609"; -} -.icon-arrow-up3:before { - content: "\e60a"; -} -.icon-arrow-right3:before { - content: "\e60b"; -} -.icon-arrow-left4:before { - content: "\e60c"; -} -.icon-arrow-down4:before { - content: "\e60d"; -} -.icon-arrow-up4:before { - content: "\e60e"; -} - -/* - * - * Ionic migration CSS - * These styles reapply foundation.css styles AFTER iconic.css has been applied. - * This has the effect of allowing all foundation styles be available at the same time as all Ionic styles being available. - * Where there are conflicts between foundation and css, this file resolves the conflict with a compromise which the developer must manage. - * This stylesheet is merged into copay.css. - */ - -/* Foundation.css styles re-applied. These styles are exactly as described in foundation.css */ - - -/* Conflicting styles that are customized as a compromise. These styles are a merge or compromise of foundation.css and ionic.css. */ - -.row { - display: inherit; -} - -.behind { - z-index: -1; -} - -.bar { - border-bottom: none; -} - -.ng-hide.ng-hide-animate { - display: none !important; -} - -.bar .title { - font-size: 14px; - line-height: 48px; -} - -.radio-label { - text-transform: none; - font-weight: 400; - font-size: 14px; -} - -.item-radio .radio-icon { - font-size: 16px; -} - -.popup-container.active .popup { - border-radius: 10px; -} - -.popup-container .popup { - width: 300px; -} - -.popup-head { - display: none; -} - -.popup-body { - padding: 0px; -} - -.bct { - background-color: transparent !important; - margin-bottom: 15px !important; -} - -.r0 { - right: 0px !important; -} - -.item { - margin: 0; - border: none; - border-bottom: 1px solid #E9E9EC; -} - -.toggle-label { - color: rgb(41, 55, 68); - font-size: 14px; -} - -button, .button { - min-width: inherit; - min-height: inherit; - text-overflow: inherit; -} - -.modal-open { - pointer-events: inherit; -} - -/* Defeat Ionic .row+.row in transaction history */ -.last-transactions-content+.last-transactions-content, .row+.last-transactions-content { - padding: 0.8rem 1rem; - cursor: pointer; - margin: inherit; -} - -/* Add margins to the session log */ -.row.columns.large-centered.medium-centered { - padding-left: 0.9375rem; - padding-right: 0.9375rem; -} - -/* Defeat Ionic .row+.row in backup failed view */ -.backup .row { - margin-top: 10px; - padding: 0; -} - -.create-tab .row { - padding: 0; -} - -/* Override the default modal size for large devices */ -@media (min-width: 680px) { - .modal { - top: 10%; - right: 20%; - bottom: 10%; - left: 20%; - min-height: 240px; - width: 60%; - } -} - - -/* - * - * Copay mobile CSS - * - */ - -/* disabling text selection */ -body { - -webkit-user-select: none; - -khtml-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-touch-callout: none !important; -} - -input { - -webkit-user-select: auto !important; - -khtml-user-select: auto !important; - -ms-user-select: auto !important; - user-select: auto !important; -} - -* { - -webkit-user-drag: none; - -ms-user-drag: none; - user-drag: none; - -webkit-tap-highlight-color:rgba(0,0,0,0); -} - -.fix-modals-touch { - -webkit-overflow-scrolling: auto; -} - -.enable_text_select { - -webkit-user-select: text; - -khtml-user-select: text; - -ms-user-select: text; - user-select: text; -} -/* END disabling text selection */ - -.inner-wrap { - -webkit-transition-duration: 200ms; - transition-duration: 200ms; - -webkit-transition-delay: 0; - transition-delay: 0; -} - -body { - overflow: hidden; - -ms-content-zooming: none; - /* removes 300ms in IE */ - -ms-touch-action: manipulation; /* IE10 */ - touch-action: manipulation; /* IE11+ */ -} - -/* Fix IE 10 */ -.extra-margin-bottom { - display: block - height: 75px - overflow: hidden - clear: both -} - -.main { - height: 99% - overflow: auto -} - -/* Fix IE 11 */ -_:-ms-fullscreen, :root .extra-margin-bottom { - display: block; - height: 75px; - overflow: hidden; - clear: both; -} - -_:-ms-fullscreen, :root .main { - height: 99%; - overflow: auto; -} - -/* Fix Firefox */ -@-moz-document url-prefix() { - .extra-margin-bottom { - display: block; - height: 45px; - overflow: hidden; - clear: both; - } -} - -@-webkit-keyframes stretchdelay { - 0%, 40%, 100% { -webkit-transform: scaleY(0.4) } - 20% { -webkit-transform: scaleY(1.0) } -} - -@keyframes stretchdelay { - 0%, 40%, 100% { - transform: scaleY(0.4); - -webkit-transform: scaleY(0.4); - } 20% { - transform: scaleY(1.0); - -webkit-transform: scaleY(1.0); - } -} - -@viewport { - width:320px; -} - -@-ms-viewport { - width:320px; - zoom-user:fixed; - max-zoom:1; - min-zoom:1; -} - -.disable-user-behavior { - -ms-touch-action: cross-slide-y !important; - touch-action: cross-slide-y !important; -} diff --git a/browser-extensions/chrome/copay-chrome-extension/css/foundation.css b/browser-extensions/chrome/copay-chrome-extension/css/foundation.css deleted file mode 100644 index bd0ee1691..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/css/foundation.css +++ /dev/null @@ -1,9944 +0,0 @@ -/* 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:not(.ng-hide-animate) { - display: none !important; -} - -ng\:form { - display: block; -} - -.ng-animate-shim { - visibility:hidden; -} - -.ng-anchor { - position:absolute; -} - -meta.foundation-version { - font-family: "/5.5.3/"; } - -meta.foundation-mq-small { - font-family: "/only screen/"; - width: 0; } - -meta.foundation-mq-small-only { - font-family: "/only screen and (max-width: 40em)/"; - width: 0; } - -meta.foundation-mq-medium { - font-family: "/only screen and (min-width:40.0625em)/"; - width: 40.0625em; } - -meta.foundation-mq-medium-only { - font-family: "/only screen and (min-width:40.0625em) and (max-width:64em)/"; - width: 40.0625em; } - -meta.foundation-mq-large { - font-family: "/only screen and (min-width:64.0625em)/"; - width: 64.0625em; } - -meta.foundation-mq-large-only { - font-family: "/only screen and (min-width:64.0625em) and (max-width:90em)/"; - width: 64.0625em; } - -meta.foundation-mq-xlarge { - font-family: "/only screen and (min-width:90.0625em)/"; - width: 90.0625em; } - -meta.foundation-mq-xlarge-only { - font-family: "/only screen and (min-width:90.0625em) and (max-width:120em)/"; - width: 90.0625em; } - -meta.foundation-mq-xxlarge { - font-family: "/only screen and (min-width:120.0625em)/"; - width: 120.0625em; } - -meta.foundation-data-attribute-namespace { - font-family: false; } - -html, body { - height: 100%; } - -*, -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; } - -html, -body { - font-size: 100%; } - -body { - background: #fff; - color: #222; - cursor: auto; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-style: normal; - font-weight: normal; - line-height: 1.5; - margin: 0; - padding: 0; - position: relative; } - -a:hover { - cursor: pointer; } - -img { - max-width: 100%; - height: auto; } - -img { - -ms-interpolation-mode: bicubic; } - -#map_canvas img, -#map_canvas embed, -#map_canvas object, -.map_canvas img, -.map_canvas embed, -.map_canvas object, -.mqa-display img, -.mqa-display embed, -.mqa-display object { - max-width: none !important; } - -.left { - float: left !important; } - -.right { - float: right !important; } - -.clearfix:before, .clearfix:after { - content: " "; - display: table; } -.clearfix:after { - clear: both; } - -.hide { - display: none; } - -.invisible { - visibility: hidden; } - -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; } - -img { - display: inline-block; - vertical-align: middle; } - -textarea { - height: auto; - min-height: 50px; } - -select { - width: 100%; } - -.row { - margin: 0 auto; - max-width: 62.5rem; - width: 100%; } - .row:before, .row:after { - content: " "; - display: table; } - .row:after { - clear: both; } - .row.collapse > .column, - .row.collapse > .columns { - padding-left: 0; - padding-right: 0; } - .row.collapse .row { - margin-left: 0; - margin-right: 0; } - .row .row { - margin: 0 -0.9375rem; - max-width: none; - width: auto; } - .row .row:before, .row .row:after { - content: " "; - display: table; } - .row .row:after { - clear: both; } - .row .row.collapse { - margin: 0; - max-width: none; - width: auto; } - .row .row.collapse:before, .row .row.collapse:after { - content: " "; - display: table; } - .row .row.collapse:after { - clear: both; } - -.column, -.columns { - padding-left: 0.9375rem; - padding-right: 0.9375rem; - width: 100%; - float: left; } - -.column + .column:last-child, -.columns + .column:last-child, .column + -.columns:last-child, -.columns + -.columns:last-child { - float: right; } -.column + .column.end, -.columns + .column.end, .column + -.columns.end, -.columns + -.columns.end { - float: left; } - -@media only screen { - .small-push-0 { - position: relative; - left: 0; - right: auto; } - - .small-pull-0 { - position: relative; - right: 0; - left: auto; } - - .small-push-1 { - position: relative; - left: 8.33333%; - right: auto; } - - .small-pull-1 { - position: relative; - right: 8.33333%; - left: auto; } - - .small-push-2 { - position: relative; - left: 16.66667%; - right: auto; } - - .small-pull-2 { - position: relative; - right: 16.66667%; - left: auto; } - - .small-push-3 { - position: relative; - left: 25%; - right: auto; } - - .small-pull-3 { - position: relative; - right: 25%; - left: auto; } - - .small-push-4 { - position: relative; - left: 33.33333%; - right: auto; } - - .small-pull-4 { - position: relative; - right: 33.33333%; - left: auto; } - - .small-push-5 { - position: relative; - left: 41.66667%; - right: auto; } - - .small-pull-5 { - position: relative; - right: 41.66667%; - left: auto; } - - .small-push-6 { - position: relative; - left: 50%; - right: auto; } - - .small-pull-6 { - position: relative; - right: 50%; - left: auto; } - - .small-push-7 { - position: relative; - left: 58.33333%; - right: auto; } - - .small-pull-7 { - position: relative; - right: 58.33333%; - left: auto; } - - .small-push-8 { - position: relative; - left: 66.66667%; - right: auto; } - - .small-pull-8 { - position: relative; - right: 66.66667%; - left: auto; } - - .small-push-9 { - position: relative; - left: 75%; - right: auto; } - - .small-pull-9 { - position: relative; - right: 75%; - left: auto; } - - .small-push-10 { - position: relative; - left: 83.33333%; - right: auto; } - - .small-pull-10 { - position: relative; - right: 83.33333%; - left: auto; } - - .small-push-11 { - position: relative; - left: 91.66667%; - right: auto; } - - .small-pull-11 { - position: relative; - right: 91.66667%; - left: auto; } - - .column, - .columns { - position: relative; - padding-left: 0.9375rem; - padding-right: 0.9375rem; - float: left; } - - .small-1 { - width: 8.33333%; } - - .small-2 { - width: 16.66667%; } - - .small-3 { - width: 25%; } - - .small-4 { - width: 33.33333%; } - - .small-5 { - width: 41.66667%; } - - .small-6 { - width: 50%; } - - .small-7 { - width: 58.33333%; } - - .small-8 { - width: 66.66667%; } - - .small-9 { - width: 75%; } - - .small-10 { - width: 83.33333%; } - - .small-11 { - width: 91.66667%; } - - .small-12 { - width: 100%; } - - .small-offset-0 { - margin-left: 0 !important; } - - .small-offset-1 { - margin-left: 8.33333% !important; } - - .small-offset-2 { - margin-left: 16.66667% !important; } - - .small-offset-3 { - margin-left: 25% !important; } - - .small-offset-4 { - margin-left: 33.33333% !important; } - - .small-offset-5 { - margin-left: 41.66667% !important; } - - .small-offset-6 { - margin-left: 50% !important; } - - .small-offset-7 { - margin-left: 58.33333% !important; } - - .small-offset-8 { - margin-left: 66.66667% !important; } - - .small-offset-9 { - margin-left: 75% !important; } - - .small-offset-10 { - margin-left: 83.33333% !important; } - - .small-offset-11 { - margin-left: 91.66667% !important; } - - .small-reset-order { - float: left; - left: auto; - margin-left: 0; - margin-right: 0; - right: auto; } - - .column.small-centered, - .columns.small-centered { - margin-left: auto; - margin-right: auto; - float: none; } - - .column.small-uncentered, - .columns.small-uncentered { - float: left; - margin-left: 0; - margin-right: 0; } - - .column.small-centered:last-child, - .columns.small-centered:last-child { - float: none; } - - .column.small-uncentered:last-child, - .columns.small-uncentered:last-child { - float: left; } - - .column.small-uncentered.opposite, - .columns.small-uncentered.opposite { - float: right; } - - .row.small-collapse > .column, - .row.small-collapse > .columns { - padding-left: 0; - padding-right: 0; } - .row.small-collapse .row { - margin-left: 0; - margin-right: 0; } - .row.small-uncollapse > .column, - .row.small-uncollapse > .columns { - padding-left: 0.9375rem; - padding-right: 0.9375rem; - float: left; } } -@media only screen and (min-width: 40.0625em) { - .medium-push-0 { - position: relative; - left: 0; - right: auto; } - - .medium-pull-0 { - position: relative; - right: 0; - left: auto; } - - .medium-push-1 { - position: relative; - left: 8.33333%; - right: auto; } - - .medium-pull-1 { - position: relative; - right: 8.33333%; - left: auto; } - - .medium-push-2 { - position: relative; - left: 16.66667%; - right: auto; } - - .medium-pull-2 { - position: relative; - right: 16.66667%; - left: auto; } - - .medium-push-3 { - position: relative; - left: 25%; - right: auto; } - - .medium-pull-3 { - position: relative; - right: 25%; - left: auto; } - - .medium-push-4 { - position: relative; - left: 33.33333%; - right: auto; } - - .medium-pull-4 { - position: relative; - right: 33.33333%; - left: auto; } - - .medium-push-5 { - position: relative; - left: 41.66667%; - right: auto; } - - .medium-pull-5 { - position: relative; - right: 41.66667%; - left: auto; } - - .medium-push-6 { - position: relative; - left: 50%; - right: auto; } - - .medium-pull-6 { - position: relative; - right: 50%; - left: auto; } - - .medium-push-7 { - position: relative; - left: 58.33333%; - right: auto; } - - .medium-pull-7 { - position: relative; - right: 58.33333%; - left: auto; } - - .medium-push-8 { - position: relative; - left: 66.66667%; - right: auto; } - - .medium-pull-8 { - position: relative; - right: 66.66667%; - left: auto; } - - .medium-push-9 { - position: relative; - left: 75%; - right: auto; } - - .medium-pull-9 { - position: relative; - right: 75%; - left: auto; } - - .medium-push-10 { - position: relative; - left: 83.33333%; - right: auto; } - - .medium-pull-10 { - position: relative; - right: 83.33333%; - left: auto; } - - .medium-push-11 { - position: relative; - left: 91.66667%; - right: auto; } - - .medium-pull-11 { - position: relative; - right: 91.66667%; - left: auto; } - - .column, - .columns { - position: relative; - padding-left: 0.9375rem; - padding-right: 0.9375rem; - float: left; } - - .medium-1 { - width: 8.33333%; } - - .medium-2 { - width: 16.66667%; } - - .medium-3 { - width: 25%; } - - .medium-4 { - width: 33.33333%; } - - .medium-5 { - width: 41.66667%; } - - .medium-6 { - width: 50%; } - - .medium-7 { - width: 58.33333%; } - - .medium-8 { - width: 66.66667%; } - - .medium-9 { - width: 75%; } - - .medium-10 { - width: 83.33333%; } - - .medium-11 { - width: 91.66667%; } - - .medium-12 { - width: 100%; } - - .medium-offset-0 { - margin-left: 0 !important; } - - .medium-offset-1 { - margin-left: 8.33333% !important; } - - .medium-offset-2 { - margin-left: 16.66667% !important; } - - .medium-offset-3 { - margin-left: 25% !important; } - - .medium-offset-4 { - margin-left: 33.33333% !important; } - - .medium-offset-5 { - margin-left: 41.66667% !important; } - - .medium-offset-6 { - margin-left: 50% !important; } - - .medium-offset-7 { - margin-left: 58.33333% !important; } - - .medium-offset-8 { - margin-left: 66.66667% !important; } - - .medium-offset-9 { - margin-left: 75% !important; } - - .medium-offset-10 { - margin-left: 83.33333% !important; } - - .medium-offset-11 { - margin-left: 91.66667% !important; } - - .medium-reset-order { - float: left; - left: auto; - margin-left: 0; - margin-right: 0; - right: auto; } - - .column.medium-centered, - .columns.medium-centered { - margin-left: auto; - margin-right: auto; - float: none; } - - .column.medium-uncentered, - .columns.medium-uncentered { - float: left; - margin-left: 0; - margin-right: 0; } - - .column.medium-centered:last-child, - .columns.medium-centered:last-child { - float: none; } - - .column.medium-uncentered:last-child, - .columns.medium-uncentered:last-child { - float: left; } - - .column.medium-uncentered.opposite, - .columns.medium-uncentered.opposite { - float: right; } - - .row.medium-collapse > .column, - .row.medium-collapse > .columns { - padding-left: 0; - padding-right: 0; } - .row.medium-collapse .row { - margin-left: 0; - margin-right: 0; } - .row.medium-uncollapse > .column, - .row.medium-uncollapse > .columns { - padding-left: 0.9375rem; - padding-right: 0.9375rem; - float: left; } - - .push-0 { - position: relative; - left: 0; - right: auto; } - - .pull-0 { - position: relative; - right: 0; - left: auto; } - - .push-1 { - position: relative; - left: 8.33333%; - right: auto; } - - .pull-1 { - position: relative; - right: 8.33333%; - left: auto; } - - .push-2 { - position: relative; - left: 16.66667%; - right: auto; } - - .pull-2 { - position: relative; - right: 16.66667%; - left: auto; } - - .push-3 { - position: relative; - left: 25%; - right: auto; } - - .pull-3 { - position: relative; - right: 25%; - left: auto; } - - .push-4 { - position: relative; - left: 33.33333%; - right: auto; } - - .pull-4 { - position: relative; - right: 33.33333%; - left: auto; } - - .push-5 { - position: relative; - left: 41.66667%; - right: auto; } - - .pull-5 { - position: relative; - right: 41.66667%; - left: auto; } - - .push-6 { - position: relative; - left: 50%; - right: auto; } - - .pull-6 { - position: relative; - right: 50%; - left: auto; } - - .push-7 { - position: relative; - left: 58.33333%; - right: auto; } - - .pull-7 { - position: relative; - right: 58.33333%; - left: auto; } - - .push-8 { - position: relative; - left: 66.66667%; - right: auto; } - - .pull-8 { - position: relative; - right: 66.66667%; - left: auto; } - - .push-9 { - position: relative; - left: 75%; - right: auto; } - - .pull-9 { - position: relative; - right: 75%; - left: auto; } - - .push-10 { - position: relative; - left: 83.33333%; - right: auto; } - - .pull-10 { - position: relative; - right: 83.33333%; - left: auto; } - - .push-11 { - position: relative; - left: 91.66667%; - right: auto; } - - .pull-11 { - position: relative; - right: 91.66667%; - left: auto; } } -@media only screen and (min-width: 64.0625em) { - .large-push-0 { - position: relative; - left: 0; - right: auto; } - - .large-pull-0 { - position: relative; - right: 0; - left: auto; } - - .large-push-1 { - position: relative; - left: 8.33333%; - right: auto; } - - .large-pull-1 { - position: relative; - right: 8.33333%; - left: auto; } - - .large-push-2 { - position: relative; - left: 16.66667%; - right: auto; } - - .large-pull-2 { - position: relative; - right: 16.66667%; - left: auto; } - - .large-push-3 { - position: relative; - left: 25%; - right: auto; } - - .large-pull-3 { - position: relative; - right: 25%; - left: auto; } - - .large-push-4 { - position: relative; - left: 33.33333%; - right: auto; } - - .large-pull-4 { - position: relative; - right: 33.33333%; - left: auto; } - - .large-push-5 { - position: relative; - left: 41.66667%; - right: auto; } - - .large-pull-5 { - position: relative; - right: 41.66667%; - left: auto; } - - .large-push-6 { - position: relative; - left: 50%; - right: auto; } - - .large-pull-6 { - position: relative; - right: 50%; - left: auto; } - - .large-push-7 { - position: relative; - left: 58.33333%; - right: auto; } - - .large-pull-7 { - position: relative; - right: 58.33333%; - left: auto; } - - .large-push-8 { - position: relative; - left: 66.66667%; - right: auto; } - - .large-pull-8 { - position: relative; - right: 66.66667%; - left: auto; } - - .large-push-9 { - position: relative; - left: 75%; - right: auto; } - - .large-pull-9 { - position: relative; - right: 75%; - left: auto; } - - .large-push-10 { - position: relative; - left: 83.33333%; - right: auto; } - - .large-pull-10 { - position: relative; - right: 83.33333%; - left: auto; } - - .large-push-11 { - position: relative; - left: 91.66667%; - right: auto; } - - .large-pull-11 { - position: relative; - right: 91.66667%; - left: auto; } - - .column, - .columns { - position: relative; - padding-left: 0.9375rem; - padding-right: 0.9375rem; - float: left; } - - .large-1 { - width: 8.33333%; } - - .large-2 { - width: 16.66667%; } - - .large-3 { - width: 25%; } - - .large-4 { - width: 33.33333%; } - - .large-5 { - width: 41.66667%; } - - .large-6 { - width: 50%; } - - .large-7 { - width: 58.33333%; } - - .large-8 { - width: 66.66667%; } - - .large-9 { - width: 75%; } - - .large-10 { - width: 83.33333%; } - - .large-11 { - width: 91.66667%; } - - .large-12 { - width: 100%; } - - .large-offset-0 { - margin-left: 0 !important; } - - .large-offset-1 { - margin-left: 8.33333% !important; } - - .large-offset-2 { - margin-left: 16.66667% !important; } - - .large-offset-3 { - margin-left: 25% !important; } - - .large-offset-4 { - margin-left: 33.33333% !important; } - - .large-offset-5 { - margin-left: 41.66667% !important; } - - .large-offset-6 { - margin-left: 50% !important; } - - .large-offset-7 { - margin-left: 58.33333% !important; } - - .large-offset-8 { - margin-left: 66.66667% !important; } - - .large-offset-9 { - margin-left: 75% !important; } - - .large-offset-10 { - margin-left: 83.33333% !important; } - - .large-offset-11 { - margin-left: 91.66667% !important; } - - .large-reset-order { - float: left; - left: auto; - margin-left: 0; - margin-right: 0; - right: auto; } - - .column.large-centered, - .columns.large-centered { - margin-left: auto; - margin-right: auto; - float: none; } - - .column.large-uncentered, - .columns.large-uncentered { - float: left; - margin-left: 0; - margin-right: 0; } - - .column.large-centered:last-child, - .columns.large-centered:last-child { - float: none; } - - .column.large-uncentered:last-child, - .columns.large-uncentered:last-child { - float: left; } - - .column.large-uncentered.opposite, - .columns.large-uncentered.opposite { - float: right; } - - .row.large-collapse > .column, - .row.large-collapse > .columns { - padding-left: 0; - padding-right: 0; } - .row.large-collapse .row { - margin-left: 0; - margin-right: 0; } - .row.large-uncollapse > .column, - .row.large-uncollapse > .columns { - padding-left: 0.9375rem; - padding-right: 0.9375rem; - float: left; } - - .push-0 { - position: relative; - left: 0; - right: auto; } - - .pull-0 { - position: relative; - right: 0; - left: auto; } - - .push-1 { - position: relative; - left: 8.33333%; - right: auto; } - - .pull-1 { - position: relative; - right: 8.33333%; - left: auto; } - - .push-2 { - position: relative; - left: 16.66667%; - right: auto; } - - .pull-2 { - position: relative; - right: 16.66667%; - left: auto; } - - .push-3 { - position: relative; - left: 25%; - right: auto; } - - .pull-3 { - position: relative; - right: 25%; - left: auto; } - - .push-4 { - position: relative; - left: 33.33333%; - right: auto; } - - .pull-4 { - position: relative; - right: 33.33333%; - left: auto; } - - .push-5 { - position: relative; - left: 41.66667%; - right: auto; } - - .pull-5 { - position: relative; - right: 41.66667%; - left: auto; } - - .push-6 { - position: relative; - left: 50%; - right: auto; } - - .pull-6 { - position: relative; - right: 50%; - left: auto; } - - .push-7 { - position: relative; - left: 58.33333%; - right: auto; } - - .pull-7 { - position: relative; - right: 58.33333%; - left: auto; } - - .push-8 { - position: relative; - left: 66.66667%; - right: auto; } - - .pull-8 { - position: relative; - right: 66.66667%; - left: auto; } - - .push-9 { - position: relative; - left: 75%; - right: auto; } - - .pull-9 { - position: relative; - right: 75%; - left: auto; } - - .push-10 { - position: relative; - left: 83.33333%; - right: auto; } - - .pull-10 { - position: relative; - right: 83.33333%; - left: auto; } - - .push-11 { - position: relative; - left: 91.66667%; - right: auto; } - - .pull-11 { - position: relative; - right: 91.66667%; - left: auto; } } -.accordion { - margin-bottom: 0; - margin-left: 0; } - .accordion:before, .accordion:after { - content: " "; - display: table; } - .accordion:after { - clear: both; } - .accordion .accordion-navigation, .accordion dd { - display: block; - margin-bottom: 0 !important; } - .accordion .accordion-navigation.active > a, .accordion dd.active > a { - background: #e8e8e8; - color: #222222; } - .accordion .accordion-navigation > a, .accordion dd > a { - background: #EFEFEF; - color: #222222; - display: block; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-size: 1rem; - padding: 1rem; } - .accordion .accordion-navigation > a:hover, .accordion dd > a:hover { - background: #e3e3e3; } - .accordion .accordion-navigation > .content, .accordion dd > .content { - display: none; - padding: 0.9375rem; } - .accordion .accordion-navigation > .content.active, .accordion dd > .content.active { - background: #FFFFFF; - display: block; } - -.alert-box { - border-style: solid; - border-width: 1px; - display: block; - font-size: 0.8125rem; - font-weight: normal; - margin-bottom: 1.25rem; - padding: 0.875rem 1.5rem 0.875rem 0.875rem; - position: relative; - transition: opacity 300ms ease-out; - background-color: #008CBA; - border-color: #0078a0; - color: #FFFFFF; } - .alert-box .close { - right: 0.25rem; - background: inherit; - color: #333333; - font-size: 1.375rem; - line-height: .9; - margin-top: -0.6875rem; - opacity: 0.3; - padding: 0 6px 4px; - position: absolute; - top: 50%; } - .alert-box .close:hover, .alert-box .close:focus { - opacity: 0.5; } - .alert-box.radius { - border-radius: 3px; } - .alert-box.round { - border-radius: 1000px; } - .alert-box.success { - background-color: #43AC6A; - border-color: #3a945b; - color: #FFFFFF; } - .alert-box.alert { - background-color: #f04124; - border-color: #de2d0f; - color: #FFFFFF; } - .alert-box.secondary { - background-color: #e7e7e7; - border-color: #c7c7c7; - color: #4f4f4f; } - .alert-box.warning { - background-color: #f08a24; - border-color: #de770f; - color: #FFFFFF; } - .alert-box.info { - background-color: #a0d3e8; - border-color: #74bfdd; - color: #4f4f4f; } - .alert-box.alert-close { - opacity: 0; } - -[class*="block-grid-"] { - display: block; - padding: 0; - margin: 0 -0.625rem; } - [class*="block-grid-"]:before, [class*="block-grid-"]:after { - content: " "; - display: table; } - [class*="block-grid-"]:after { - clear: both; } - [class*="block-grid-"] > li { - display: block; - float: left; - height: auto; - padding: 0 0.625rem 1.25rem; } - -@media only screen { - .small-block-grid-1 > li { - list-style: none; - width: 100%; } - .small-block-grid-1 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-1 > li:nth-of-type(1n+1) { - clear: both; } - - .small-block-grid-2 > li { - list-style: none; - width: 50%; } - .small-block-grid-2 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-2 > li:nth-of-type(2n+1) { - clear: both; } - - .small-block-grid-3 > li { - list-style: none; - width: 33.33333%; } - .small-block-grid-3 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-3 > li:nth-of-type(3n+1) { - clear: both; } - - .small-block-grid-4 > li { - list-style: none; - width: 25%; } - .small-block-grid-4 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-4 > li:nth-of-type(4n+1) { - clear: both; } - - .small-block-grid-5 > li { - list-style: none; - width: 20%; } - .small-block-grid-5 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-5 > li:nth-of-type(5n+1) { - clear: both; } - - .small-block-grid-6 > li { - list-style: none; - width: 16.66667%; } - .small-block-grid-6 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-6 > li:nth-of-type(6n+1) { - clear: both; } - - .small-block-grid-7 > li { - list-style: none; - width: 14.28571%; } - .small-block-grid-7 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-7 > li:nth-of-type(7n+1) { - clear: both; } - - .small-block-grid-8 > li { - list-style: none; - width: 12.5%; } - .small-block-grid-8 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-8 > li:nth-of-type(8n+1) { - clear: both; } - - .small-block-grid-9 > li { - list-style: none; - width: 11.11111%; } - .small-block-grid-9 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-9 > li:nth-of-type(9n+1) { - clear: both; } - - .small-block-grid-10 > li { - list-style: none; - width: 10%; } - .small-block-grid-10 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-10 > li:nth-of-type(10n+1) { - clear: both; } - - .small-block-grid-11 > li { - list-style: none; - width: 9.09091%; } - .small-block-grid-11 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-11 > li:nth-of-type(11n+1) { - clear: both; } - - .small-block-grid-12 > li { - list-style: none; - width: 8.33333%; } - .small-block-grid-12 > li:nth-of-type(1n) { - clear: none; } - .small-block-grid-12 > li:nth-of-type(12n+1) { - clear: both; } } -@media only screen and (min-width: 40.0625em) { - .medium-block-grid-1 > li { - list-style: none; - width: 100%; } - .medium-block-grid-1 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-1 > li:nth-of-type(1n+1) { - clear: both; } - - .medium-block-grid-2 > li { - list-style: none; - width: 50%; } - .medium-block-grid-2 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-2 > li:nth-of-type(2n+1) { - clear: both; } - - .medium-block-grid-3 > li { - list-style: none; - width: 33.33333%; } - .medium-block-grid-3 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-3 > li:nth-of-type(3n+1) { - clear: both; } - - .medium-block-grid-4 > li { - list-style: none; - width: 25%; } - .medium-block-grid-4 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-4 > li:nth-of-type(4n+1) { - clear: both; } - - .medium-block-grid-5 > li { - list-style: none; - width: 20%; } - .medium-block-grid-5 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-5 > li:nth-of-type(5n+1) { - clear: both; } - - .medium-block-grid-6 > li { - list-style: none; - width: 16.66667%; } - .medium-block-grid-6 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-6 > li:nth-of-type(6n+1) { - clear: both; } - - .medium-block-grid-7 > li { - list-style: none; - width: 14.28571%; } - .medium-block-grid-7 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-7 > li:nth-of-type(7n+1) { - clear: both; } - - .medium-block-grid-8 > li { - list-style: none; - width: 12.5%; } - .medium-block-grid-8 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-8 > li:nth-of-type(8n+1) { - clear: both; } - - .medium-block-grid-9 > li { - list-style: none; - width: 11.11111%; } - .medium-block-grid-9 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-9 > li:nth-of-type(9n+1) { - clear: both; } - - .medium-block-grid-10 > li { - list-style: none; - width: 10%; } - .medium-block-grid-10 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-10 > li:nth-of-type(10n+1) { - clear: both; } - - .medium-block-grid-11 > li { - list-style: none; - width: 9.09091%; } - .medium-block-grid-11 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-11 > li:nth-of-type(11n+1) { - clear: both; } - - .medium-block-grid-12 > li { - list-style: none; - width: 8.33333%; } - .medium-block-grid-12 > li:nth-of-type(1n) { - clear: none; } - .medium-block-grid-12 > li:nth-of-type(12n+1) { - clear: both; } } -@media only screen and (min-width: 64.0625em) { - .large-block-grid-1 > li { - list-style: none; - width: 100%; } - .large-block-grid-1 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-1 > li:nth-of-type(1n+1) { - clear: both; } - - .large-block-grid-2 > li { - list-style: none; - width: 50%; } - .large-block-grid-2 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-2 > li:nth-of-type(2n+1) { - clear: both; } - - .large-block-grid-3 > li { - list-style: none; - width: 33.33333%; } - .large-block-grid-3 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-3 > li:nth-of-type(3n+1) { - clear: both; } - - .large-block-grid-4 > li { - list-style: none; - width: 25%; } - .large-block-grid-4 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-4 > li:nth-of-type(4n+1) { - clear: both; } - - .large-block-grid-5 > li { - list-style: none; - width: 20%; } - .large-block-grid-5 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-5 > li:nth-of-type(5n+1) { - clear: both; } - - .large-block-grid-6 > li { - list-style: none; - width: 16.66667%; } - .large-block-grid-6 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-6 > li:nth-of-type(6n+1) { - clear: both; } - - .large-block-grid-7 > li { - list-style: none; - width: 14.28571%; } - .large-block-grid-7 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-7 > li:nth-of-type(7n+1) { - clear: both; } - - .large-block-grid-8 > li { - list-style: none; - width: 12.5%; } - .large-block-grid-8 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-8 > li:nth-of-type(8n+1) { - clear: both; } - - .large-block-grid-9 > li { - list-style: none; - width: 11.11111%; } - .large-block-grid-9 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-9 > li:nth-of-type(9n+1) { - clear: both; } - - .large-block-grid-10 > li { - list-style: none; - width: 10%; } - .large-block-grid-10 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-10 > li:nth-of-type(10n+1) { - clear: both; } - - .large-block-grid-11 > li { - list-style: none; - width: 9.09091%; } - .large-block-grid-11 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-11 > li:nth-of-type(11n+1) { - clear: both; } - - .large-block-grid-12 > li { - list-style: none; - width: 8.33333%; } - .large-block-grid-12 > li:nth-of-type(1n) { - clear: none; } - .large-block-grid-12 > li:nth-of-type(12n+1) { - clear: both; } } -.breadcrumbs { - border-style: solid; - border-width: 1px; - display: block; - list-style: none; - margin-left: 0; - overflow: hidden; - padding: 0.5625rem 0.875rem 0.5625rem; - background-color: #f4f4f4; - border-color: gainsboro; - border-radius: 3px; } - .breadcrumbs > * { - color: #008CBA; - float: left; - font-size: 0.6875rem; - line-height: 0.6875rem; - margin: 0; - text-transform: uppercase; } - .breadcrumbs > *:hover a, .breadcrumbs > *:focus a { - text-decoration: underline; } - .breadcrumbs > * a { - color: #008CBA; } - .breadcrumbs > *.current { - color: #333333; - cursor: default; } - .breadcrumbs > *.current a { - color: #333333; - cursor: default; } - .breadcrumbs > *.current:hover, .breadcrumbs > *.current:hover a, .breadcrumbs > *.current:focus, .breadcrumbs > *.current:focus a { - text-decoration: none; } - .breadcrumbs > *.unavailable { - color: #999999; } - .breadcrumbs > *.unavailable a { - color: #999999; } - .breadcrumbs > *.unavailable:hover, .breadcrumbs > *.unavailable:hover a, .breadcrumbs > *.unavailable:focus, - .breadcrumbs > *.unavailable a:focus { - color: #999999; - cursor: not-allowed; - text-decoration: none; } - .breadcrumbs > *:before { - color: #AAAAAA; - content: "/"; - margin: 0 0.75rem; - position: relative; - top: 1px; } - .breadcrumbs > *:first-child:before { - content: " "; - margin: 0; } - -/* Accessibility - hides the forward slash */ -[aria-label="breadcrumbs"] [aria-hidden="true"]:after { - content: "/"; } - -button, .button { - -webkit-appearance: none; - -moz-appearance: none; - border-radius: 0; - border-style: solid; - border-width: 0; - cursor: pointer; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-weight: normal; - line-height: normal; - margin: 0 0 1.25rem; - position: relative; - text-align: center; - text-decoration: none; - display: inline-block; - padding: 1rem 2rem 1.0625rem 2rem; - font-size: 1rem; - background-color: #008CBA; - border-color: #007095; - color: #FFFFFF; - transition: background-color 300ms ease-out; } - button:hover, button:focus, .button:hover, .button:focus { - background-color: #007095; } - button:hover, button:focus, .button:hover, .button:focus { - color: #FFFFFF; } - button.secondary, .button.secondary { - background-color: #e7e7e7; - border-color: #b9b9b9; - color: #333333; } - button.secondary:hover, button.secondary:focus, .button.secondary:hover, .button.secondary:focus { - background-color: #b9b9b9; } - button.secondary:hover, button.secondary:focus, .button.secondary:hover, .button.secondary:focus { - color: #333333; } - button.success, .button.success { - background-color: #43AC6A; - border-color: #368a55; - color: #FFFFFF; } - button.success:hover, button.success:focus, .button.success:hover, .button.success:focus { - background-color: #368a55; } - button.success:hover, button.success:focus, .button.success:hover, .button.success:focus { - color: #FFFFFF; } - button.alert, .button.alert { - background-color: #f04124; - border-color: #cf2a0e; - color: #FFFFFF; } - button.alert:hover, button.alert:focus, .button.alert:hover, .button.alert:focus { - background-color: #cf2a0e; } - button.alert:hover, button.alert:focus, .button.alert:hover, .button.alert:focus { - color: #FFFFFF; } - button.warning, .button.warning { - background-color: #f08a24; - border-color: #cf6e0e; - color: #FFFFFF; } - button.warning:hover, button.warning:focus, .button.warning:hover, .button.warning:focus { - background-color: #cf6e0e; } - button.warning:hover, button.warning:focus, .button.warning:hover, .button.warning:focus { - color: #FFFFFF; } - button.info, .button.info { - background-color: #a0d3e8; - border-color: #61b6d9; - color: #333333; } - button.info:hover, button.info:focus, .button.info:hover, .button.info:focus { - background-color: #61b6d9; } - button.info:hover, button.info:focus, .button.info:hover, .button.info:focus { - color: #FFFFFF; } - button.large, .button.large { - padding: 1.125rem 2.25rem 1.1875rem 2.25rem; - font-size: 1.25rem; } - button.small, .button.small { - padding: 0.875rem 1.75rem 0.9375rem 1.75rem; - font-size: 0.8125rem; } - button.tiny, .button.tiny { - padding: 0.625rem 1.25rem 0.6875rem 1.25rem; - font-size: 0.6875rem; } - button.expand, .button.expand { - padding: 1rem 2rem 1.0625rem 2rem; - font-size: 1rem; - padding-bottom: 1.0625rem; - padding-top: 1rem; - padding-left: 1rem; - padding-right: 1rem; - width: 100%; } - button.left-align, .button.left-align { - text-align: left; - text-indent: 0.75rem; } - button.right-align, .button.right-align { - text-align: right; - padding-right: 0.75rem; } - button.radius, .button.radius { - border-radius: 3px; } - button.round, .button.round { - border-radius: 1000px; } - button.disabled, button[disabled], .button.disabled, .button[disabled] { - background-color: #008CBA; - border-color: #007095; - color: #FFFFFF; - box-shadow: none; - cursor: default; - opacity: 0.7; } - button.disabled:hover, button.disabled:focus, button[disabled]:hover, button[disabled]:focus, .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus { - background-color: #007095; } - button.disabled:hover, button.disabled:focus, button[disabled]:hover, button[disabled]:focus, .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus { - color: #FFFFFF; } - button.disabled:hover, button.disabled:focus, button[disabled]:hover, button[disabled]:focus, .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus { - background-color: #008CBA; } - button.disabled.secondary, button[disabled].secondary, .button.disabled.secondary, .button[disabled].secondary { - background-color: #e7e7e7; - border-color: #b9b9b9; - color: #333333; - box-shadow: none; - cursor: default; - opacity: 0.7; } - button.disabled.secondary:hover, button.disabled.secondary:focus, button[disabled].secondary:hover, button[disabled].secondary:focus, .button.disabled.secondary:hover, .button.disabled.secondary:focus, .button[disabled].secondary:hover, .button[disabled].secondary:focus { - background-color: #b9b9b9; } - button.disabled.secondary:hover, button.disabled.secondary:focus, button[disabled].secondary:hover, button[disabled].secondary:focus, .button.disabled.secondary:hover, .button.disabled.secondary:focus, .button[disabled].secondary:hover, .button[disabled].secondary:focus { - color: #333333; } - button.disabled.secondary:hover, button.disabled.secondary:focus, button[disabled].secondary:hover, button[disabled].secondary:focus, .button.disabled.secondary:hover, .button.disabled.secondary:focus, .button[disabled].secondary:hover, .button[disabled].secondary:focus { - background-color: #e7e7e7; } - button.disabled.success, button[disabled].success, .button.disabled.success, .button[disabled].success { - background-color: #43AC6A; - border-color: #368a55; - color: #FFFFFF; - box-shadow: none; - cursor: default; - opacity: 0.7; } - button.disabled.success:hover, button.disabled.success:focus, button[disabled].success:hover, button[disabled].success:focus, .button.disabled.success:hover, .button.disabled.success:focus, .button[disabled].success:hover, .button[disabled].success:focus { - background-color: #368a55; } - button.disabled.success:hover, button.disabled.success:focus, button[disabled].success:hover, button[disabled].success:focus, .button.disabled.success:hover, .button.disabled.success:focus, .button[disabled].success:hover, .button[disabled].success:focus { - color: #FFFFFF; } - button.disabled.success:hover, button.disabled.success:focus, button[disabled].success:hover, button[disabled].success:focus, .button.disabled.success:hover, .button.disabled.success:focus, .button[disabled].success:hover, .button[disabled].success:focus { - background-color: #43AC6A; } - button.disabled.alert, button[disabled].alert, .button.disabled.alert, .button[disabled].alert { - background-color: #f04124; - border-color: #cf2a0e; - color: #FFFFFF; - box-shadow: none; - cursor: default; - opacity: 0.7; } - button.disabled.alert:hover, button.disabled.alert:focus, button[disabled].alert:hover, button[disabled].alert:focus, .button.disabled.alert:hover, .button.disabled.alert:focus, .button[disabled].alert:hover, .button[disabled].alert:focus { - background-color: #cf2a0e; } - button.disabled.alert:hover, button.disabled.alert:focus, button[disabled].alert:hover, button[disabled].alert:focus, .button.disabled.alert:hover, .button.disabled.alert:focus, .button[disabled].alert:hover, .button[disabled].alert:focus { - color: #FFFFFF; } - button.disabled.alert:hover, button.disabled.alert:focus, button[disabled].alert:hover, button[disabled].alert:focus, .button.disabled.alert:hover, .button.disabled.alert:focus, .button[disabled].alert:hover, .button[disabled].alert:focus { - background-color: #f04124; } - button.disabled.warning, button[disabled].warning, .button.disabled.warning, .button[disabled].warning { - background-color: #f08a24; - border-color: #cf6e0e; - color: #FFFFFF; - box-shadow: none; - cursor: default; - opacity: 0.7; } - button.disabled.warning:hover, button.disabled.warning:focus, button[disabled].warning:hover, button[disabled].warning:focus, .button.disabled.warning:hover, .button.disabled.warning:focus, .button[disabled].warning:hover, .button[disabled].warning:focus { - background-color: #cf6e0e; } - button.disabled.warning:hover, button.disabled.warning:focus, button[disabled].warning:hover, button[disabled].warning:focus, .button.disabled.warning:hover, .button.disabled.warning:focus, .button[disabled].warning:hover, .button[disabled].warning:focus { - color: #FFFFFF; } - button.disabled.warning:hover, button.disabled.warning:focus, button[disabled].warning:hover, button[disabled].warning:focus, .button.disabled.warning:hover, .button.disabled.warning:focus, .button[disabled].warning:hover, .button[disabled].warning:focus { - background-color: #f08a24; } - button.disabled.info, button[disabled].info, .button.disabled.info, .button[disabled].info { - background-color: #a0d3e8; - border-color: #61b6d9; - color: #333333; - box-shadow: none; - cursor: default; - opacity: 0.7; } - button.disabled.info:hover, button.disabled.info:focus, button[disabled].info:hover, button[disabled].info:focus, .button.disabled.info:hover, .button.disabled.info:focus, .button[disabled].info:hover, .button[disabled].info:focus { - background-color: #61b6d9; } - button.disabled.info:hover, button.disabled.info:focus, button[disabled].info:hover, button[disabled].info:focus, .button.disabled.info:hover, .button.disabled.info:focus, .button[disabled].info:hover, .button[disabled].info:focus { - color: #FFFFFF; } - button.disabled.info:hover, button.disabled.info:focus, button[disabled].info:hover, button[disabled].info:focus, .button.disabled.info:hover, .button.disabled.info:focus, .button[disabled].info:hover, .button[disabled].info:focus { - background-color: #a0d3e8; } - -button::-moz-focus-inner { - border: 0; - padding: 0; } - -@media only screen and (min-width: 40.0625em) { - button, .button { - display: inline-block; } } -.button-group { - list-style: none; - margin: 0; - left: 0; } - .button-group:before, .button-group:after { - content: " "; - display: table; } - .button-group:after { - clear: both; } - .button-group.even-2 li { - display: inline-block; - margin: 0 -2px; - width: 50%; } - .button-group.even-2 li > button, .button-group.even-2 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-2 li:first-child button, .button-group.even-2 li:first-child .button { - border-left: 0; } - .button-group.even-2 li button, .button-group.even-2 li .button { - width: 100%; } - .button-group.even-3 li { - display: inline-block; - margin: 0 -2px; - width: 33.33333%; } - .button-group.even-3 li > button, .button-group.even-3 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-3 li:first-child button, .button-group.even-3 li:first-child .button { - border-left: 0; } - .button-group.even-3 li button, .button-group.even-3 li .button { - width: 100%; } - .button-group.even-4 li { - display: inline-block; - margin: 0 -2px; - width: 25%; } - .button-group.even-4 li > button, .button-group.even-4 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-4 li:first-child button, .button-group.even-4 li:first-child .button { - border-left: 0; } - .button-group.even-4 li button, .button-group.even-4 li .button { - width: 100%; } - .button-group.even-5 li { - display: inline-block; - margin: 0 -2px; - width: 20%; } - .button-group.even-5 li > button, .button-group.even-5 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-5 li:first-child button, .button-group.even-5 li:first-child .button { - border-left: 0; } - .button-group.even-5 li button, .button-group.even-5 li .button { - width: 100%; } - .button-group.even-6 li { - display: inline-block; - margin: 0 -2px; - width: 16.66667%; } - .button-group.even-6 li > button, .button-group.even-6 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-6 li:first-child button, .button-group.even-6 li:first-child .button { - border-left: 0; } - .button-group.even-6 li button, .button-group.even-6 li .button { - width: 100%; } - .button-group.even-7 li { - display: inline-block; - margin: 0 -2px; - width: 14.28571%; } - .button-group.even-7 li > button, .button-group.even-7 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-7 li:first-child button, .button-group.even-7 li:first-child .button { - border-left: 0; } - .button-group.even-7 li button, .button-group.even-7 li .button { - width: 100%; } - .button-group.even-8 li { - display: inline-block; - margin: 0 -2px; - width: 12.5%; } - .button-group.even-8 li > button, .button-group.even-8 li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.even-8 li:first-child button, .button-group.even-8 li:first-child .button { - border-left: 0; } - .button-group.even-8 li button, .button-group.even-8 li .button { - width: 100%; } - .button-group > li { - display: inline-block; - margin: 0 -2px; } - .button-group > li > button, .button-group > li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group > li:first-child button, .button-group > li:first-child .button { - border-left: 0; } - .button-group.stack > li { - display: block; - margin: 0; - float: none; } - .button-group.stack > li > button, .button-group.stack > li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.stack > li:first-child button, .button-group.stack > li:first-child .button { - border-left: 0; } - .button-group.stack > li > button, .button-group.stack > li .button { - border-color: rgba(255, 255, 255, 0.5); - border-left-width: 0; - border-top: 1px solid; - display: block; - margin: 0; } - .button-group.stack > li > button { - width: 100%; } - .button-group.stack > li:first-child button, .button-group.stack > li:first-child .button { - border-top: 0; } - .button-group.stack-for-small > li { - display: inline-block; - margin: 0 -2px; } - .button-group.stack-for-small > li > button, .button-group.stack-for-small > li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.stack-for-small > li:first-child button, .button-group.stack-for-small > li:first-child .button { - border-left: 0; } - @media only screen and (max-width: 40em) { - .button-group.stack-for-small > li { - display: block; - margin: 0; - width: 100%; } - .button-group.stack-for-small > li > button, .button-group.stack-for-small > li .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.stack-for-small > li:first-child button, .button-group.stack-for-small > li:first-child .button { - border-left: 0; } - .button-group.stack-for-small > li > button, .button-group.stack-for-small > li .button { - border-color: rgba(255, 255, 255, 0.5); - border-left-width: 0; - border-top: 1px solid; - display: block; - margin: 0; } - .button-group.stack-for-small > li > button { - width: 100%; } - .button-group.stack-for-small > li:first-child button, .button-group.stack-for-small > li:first-child .button { - border-top: 0; } } - .button-group.radius > * { - display: inline-block; - margin: 0 -2px; } - .button-group.radius > * > button, .button-group.radius > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.radius > *:first-child button, .button-group.radius > *:first-child .button { - border-left: 0; } - .button-group.radius > *, - .button-group.radius > * > a, - .button-group.radius > * > button, - .button-group.radius > * > .button { - border-radius: 0; } - .button-group.radius > *:first-child, .button-group.radius > *:first-child > a, .button-group.radius > *:first-child > button, .button-group.radius > *:first-child > .button { - -webkit-border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; } - .button-group.radius > *:last-child, .button-group.radius > *:last-child > a, .button-group.radius > *:last-child > button, .button-group.radius > *:last-child > .button { - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } - .button-group.radius.stack > * { - display: block; - margin: 0; } - .button-group.radius.stack > * > button, .button-group.radius.stack > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.radius.stack > *:first-child button, .button-group.radius.stack > *:first-child .button { - border-left: 0; } - .button-group.radius.stack > * > button, .button-group.radius.stack > * .button { - border-color: rgba(255, 255, 255, 0.5); - border-left-width: 0; - border-top: 1px solid; - display: block; - margin: 0; } - .button-group.radius.stack > * > button { - width: 100%; } - .button-group.radius.stack > *:first-child button, .button-group.radius.stack > *:first-child .button { - border-top: 0; } - .button-group.radius.stack > *, - .button-group.radius.stack > * > a, - .button-group.radius.stack > * > button, - .button-group.radius.stack > * > .button { - border-radius: 0; } - .button-group.radius.stack > *:first-child, .button-group.radius.stack > *:first-child > a, .button-group.radius.stack > *:first-child > button, .button-group.radius.stack > *:first-child > .button { - -webkit-top-left-radius: 3px; - -webkit-top-right-radius: 3px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; } - .button-group.radius.stack > *:last-child, .button-group.radius.stack > *:last-child > a, .button-group.radius.stack > *:last-child > button, .button-group.radius.stack > *:last-child > .button { - -webkit-bottom-left-radius: 3px; - -webkit-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; } - @media only screen and (min-width: 40.0625em) { - .button-group.radius.stack-for-small > * { - display: inline-block; - margin: 0 -2px; } - .button-group.radius.stack-for-small > * > button, .button-group.radius.stack-for-small > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.radius.stack-for-small > *:first-child button, .button-group.radius.stack-for-small > *:first-child .button { - border-left: 0; } - .button-group.radius.stack-for-small > *, - .button-group.radius.stack-for-small > * > a, - .button-group.radius.stack-for-small > * > button, - .button-group.radius.stack-for-small > * > .button { - border-radius: 0; } - .button-group.radius.stack-for-small > *:first-child, .button-group.radius.stack-for-small > *:first-child > a, .button-group.radius.stack-for-small > *:first-child > button, .button-group.radius.stack-for-small > *:first-child > .button { - -webkit-border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; } - .button-group.radius.stack-for-small > *:last-child, .button-group.radius.stack-for-small > *:last-child > a, .button-group.radius.stack-for-small > *:last-child > button, .button-group.radius.stack-for-small > *:last-child > .button { - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } } - @media only screen and (max-width: 40em) { - .button-group.radius.stack-for-small > * { - display: block; - margin: 0; } - .button-group.radius.stack-for-small > * > button, .button-group.radius.stack-for-small > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.radius.stack-for-small > *:first-child button, .button-group.radius.stack-for-small > *:first-child .button { - border-left: 0; } - .button-group.radius.stack-for-small > * > button, .button-group.radius.stack-for-small > * .button { - border-color: rgba(255, 255, 255, 0.5); - border-left-width: 0; - border-top: 1px solid; - display: block; - margin: 0; } - .button-group.radius.stack-for-small > * > button { - width: 100%; } - .button-group.radius.stack-for-small > *:first-child button, .button-group.radius.stack-for-small > *:first-child .button { - border-top: 0; } - .button-group.radius.stack-for-small > *, - .button-group.radius.stack-for-small > * > a, - .button-group.radius.stack-for-small > * > button, - .button-group.radius.stack-for-small > * > .button { - border-radius: 0; } - .button-group.radius.stack-for-small > *:first-child, .button-group.radius.stack-for-small > *:first-child > a, .button-group.radius.stack-for-small > *:first-child > button, .button-group.radius.stack-for-small > *:first-child > .button { - -webkit-top-left-radius: 3px; - -webkit-top-right-radius: 3px; - border-top-left-radius: 3px; - border-top-right-radius: 3px; } - .button-group.radius.stack-for-small > *:last-child, .button-group.radius.stack-for-small > *:last-child > a, .button-group.radius.stack-for-small > *:last-child > button, .button-group.radius.stack-for-small > *:last-child > .button { - -webkit-bottom-left-radius: 3px; - -webkit-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; - border-bottom-right-radius: 3px; } } - .button-group.round > * { - display: inline-block; - margin: 0 -2px; } - .button-group.round > * > button, .button-group.round > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.round > *:first-child button, .button-group.round > *:first-child .button { - border-left: 0; } - .button-group.round > *, - .button-group.round > * > a, - .button-group.round > * > button, - .button-group.round > * > .button { - border-radius: 0; } - .button-group.round > *:first-child, .button-group.round > *:first-child > a, .button-group.round > *:first-child > button, .button-group.round > *:first-child > .button { - -webkit-border-bottom-left-radius: 1000px; - -webkit-border-top-left-radius: 1000px; - border-bottom-left-radius: 1000px; - border-top-left-radius: 1000px; } - .button-group.round > *:last-child, .button-group.round > *:last-child > a, .button-group.round > *:last-child > button, .button-group.round > *:last-child > .button { - -webkit-border-bottom-right-radius: 1000px; - -webkit-border-top-right-radius: 1000px; - border-bottom-right-radius: 1000px; - border-top-right-radius: 1000px; } - .button-group.round.stack > * { - display: block; - margin: 0; } - .button-group.round.stack > * > button, .button-group.round.stack > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.round.stack > *:first-child button, .button-group.round.stack > *:first-child .button { - border-left: 0; } - .button-group.round.stack > * > button, .button-group.round.stack > * .button { - border-color: rgba(255, 255, 255, 0.5); - border-left-width: 0; - border-top: 1px solid; - display: block; - margin: 0; } - .button-group.round.stack > * > button { - width: 100%; } - .button-group.round.stack > *:first-child button, .button-group.round.stack > *:first-child .button { - border-top: 0; } - .button-group.round.stack > *, - .button-group.round.stack > * > a, - .button-group.round.stack > * > button, - .button-group.round.stack > * > .button { - border-radius: 0; } - .button-group.round.stack > *:first-child, .button-group.round.stack > *:first-child > a, .button-group.round.stack > *:first-child > button, .button-group.round.stack > *:first-child > .button { - -webkit-top-left-radius: 1rem; - -webkit-top-right-radius: 1rem; - border-top-left-radius: 1rem; - border-top-right-radius: 1rem; } - .button-group.round.stack > *:last-child, .button-group.round.stack > *:last-child > a, .button-group.round.stack > *:last-child > button, .button-group.round.stack > *:last-child > .button { - -webkit-bottom-left-radius: 1rem; - -webkit-bottom-right-radius: 1rem; - border-bottom-left-radius: 1rem; - border-bottom-right-radius: 1rem; } - @media only screen and (min-width: 40.0625em) { - .button-group.round.stack-for-small > * { - display: inline-block; - margin: 0 -2px; } - .button-group.round.stack-for-small > * > button, .button-group.round.stack-for-small > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.round.stack-for-small > *:first-child button, .button-group.round.stack-for-small > *:first-child .button { - border-left: 0; } - .button-group.round.stack-for-small > *, - .button-group.round.stack-for-small > * > a, - .button-group.round.stack-for-small > * > button, - .button-group.round.stack-for-small > * > .button { - border-radius: 0; } - .button-group.round.stack-for-small > *:first-child, .button-group.round.stack-for-small > *:first-child > a, .button-group.round.stack-for-small > *:first-child > button, .button-group.round.stack-for-small > *:first-child > .button { - -webkit-border-bottom-left-radius: 1000px; - -webkit-border-top-left-radius: 1000px; - border-bottom-left-radius: 1000px; - border-top-left-radius: 1000px; } - .button-group.round.stack-for-small > *:last-child, .button-group.round.stack-for-small > *:last-child > a, .button-group.round.stack-for-small > *:last-child > button, .button-group.round.stack-for-small > *:last-child > .button { - -webkit-border-bottom-right-radius: 1000px; - -webkit-border-top-right-radius: 1000px; - border-bottom-right-radius: 1000px; - border-top-right-radius: 1000px; } } - @media only screen and (max-width: 40em) { - .button-group.round.stack-for-small > * { - display: block; - margin: 0; } - .button-group.round.stack-for-small > * > button, .button-group.round.stack-for-small > * .button { - border-left: 1px solid; - border-color: rgba(255, 255, 255, 0.5); } - .button-group.round.stack-for-small > *:first-child button, .button-group.round.stack-for-small > *:first-child .button { - border-left: 0; } - .button-group.round.stack-for-small > * > button, .button-group.round.stack-for-small > * .button { - border-color: rgba(255, 255, 255, 0.5); - border-left-width: 0; - border-top: 1px solid; - display: block; - margin: 0; } - .button-group.round.stack-for-small > * > button { - width: 100%; } - .button-group.round.stack-for-small > *:first-child button, .button-group.round.stack-for-small > *:first-child .button { - border-top: 0; } - .button-group.round.stack-for-small > *, - .button-group.round.stack-for-small > * > a, - .button-group.round.stack-for-small > * > button, - .button-group.round.stack-for-small > * > .button { - border-radius: 0; } - .button-group.round.stack-for-small > *:first-child, .button-group.round.stack-for-small > *:first-child > a, .button-group.round.stack-for-small > *:first-child > button, .button-group.round.stack-for-small > *:first-child > .button { - -webkit-top-left-radius: 1rem; - -webkit-top-right-radius: 1rem; - border-top-left-radius: 1rem; - border-top-right-radius: 1rem; } - .button-group.round.stack-for-small > *:last-child, .button-group.round.stack-for-small > *:last-child > a, .button-group.round.stack-for-small > *:last-child > button, .button-group.round.stack-for-small > *:last-child > .button { - -webkit-bottom-left-radius: 1rem; - -webkit-bottom-right-radius: 1rem; - border-bottom-left-radius: 1rem; - border-bottom-right-radius: 1rem; } } - -.button-bar:before, .button-bar:after { - content: " "; - display: table; } -.button-bar:after { - clear: both; } -.button-bar .button-group { - float: left; - margin-right: 0.625rem; } - .button-bar .button-group div { - overflow: hidden; } - -/* Clearing Styles */ -.clearing-thumbs, [data-clearing] { - list-style: none; - margin-left: 0; - margin-bottom: 0; } - .clearing-thumbs:before, .clearing-thumbs:after, [data-clearing]:before, [data-clearing]:after { - content: " "; - display: table; } - .clearing-thumbs:after, [data-clearing]:after { - clear: both; } - .clearing-thumbs li, [data-clearing] li { - float: left; - margin-right: 10px; } - .clearing-thumbs[class*="block-grid-"] li, [data-clearing][class*="block-grid-"] li { - margin-right: 0; } - -.clearing-blackout { - background: #333333; - height: 100%; - position: fixed; - top: 0; - width: 100%; - z-index: 998; - left: 0; } - .clearing-blackout .clearing-close { - display: block; } - -.clearing-container { - height: 100%; - margin: 0; - overflow: hidden; - position: relative; - z-index: 998; } - -.clearing-touch-label { - color: #AAAAAA; - font-size: .6em; - left: 50%; - position: absolute; - top: 50%; } - -.visible-img { - height: 95%; - position: relative; } - .visible-img img { - position: absolute; - left: 50%; - top: 50%; - -webkit-transform: translateY(-50%) translateX(-50%); - -moz-transform: translateY(-50%) translateX(-50%); - -ms-transform: translateY(-50%) translateX(-50%); - -o-transform: translateY(-50%) translateX(-50%); - transform: translateY(-50%) translateX(-50%); - max-height: 100%; - max-width: 100%; } - -.clearing-caption { - background: #333333; - bottom: 0; - color: #CCCCCC; - font-size: 0.875em; - line-height: 1.3; - margin-bottom: 0; - padding: 10px 30px 20px; - position: absolute; - text-align: center; - width: 100%; - left: 0; } - -.clearing-close { - color: #CCCCCC; - display: none; - font-size: 30px; - line-height: 1; - padding-left: 20px; - padding-top: 10px; - z-index: 999; } - .clearing-close:hover, .clearing-close:focus { - color: #CCCCCC; } - -.clearing-assembled .clearing-container { - height: 100%; } - .clearing-assembled .clearing-container .carousel > ul { - display: none; } - -.clearing-feature li { - display: none; } - .clearing-feature li.clearing-featured-img { - display: block; } - -@media only screen and (min-width: 40.0625em) { - .clearing-main-prev, - .clearing-main-next { - height: 100%; - position: absolute; - top: 0; - width: 40px; } - .clearing-main-prev > span, - .clearing-main-next > span { - border: solid 12px; - display: block; - height: 0; - position: absolute; - top: 50%; - width: 0; } - .clearing-main-prev > span:hover, - .clearing-main-next > span:hover { - opacity: .8; } - - .clearing-main-prev { - left: 0; } - .clearing-main-prev > span { - left: 5px; - border-color: transparent; - border-right-color: #CCCCCC; } - - .clearing-main-next { - right: 0; } - .clearing-main-next > span { - border-color: transparent; - border-left-color: #CCCCCC; } - - .clearing-main-prev.disabled, - .clearing-main-next.disabled { - opacity: .3; } - - .clearing-assembled .clearing-container .carousel { - background: rgba(51, 51, 51, 0.8); - height: 120px; - margin-top: 10px; - text-align: center; } - .clearing-assembled .clearing-container .carousel > ul { - display: inline-block; - z-index: 999; - height: 100%; - position: relative; - float: none; } - .clearing-assembled .clearing-container .carousel > ul li { - clear: none; - cursor: pointer; - display: block; - float: left; - margin-right: 0; - min-height: inherit; - opacity: .4; - overflow: hidden; - padding: 0; - position: relative; - width: 120px; } - .clearing-assembled .clearing-container .carousel > ul li.fix-height img { - height: 100%; - max-width: none; } - .clearing-assembled .clearing-container .carousel > ul li a.th { - border: none; - box-shadow: none; - display: block; } - .clearing-assembled .clearing-container .carousel > ul li img { - cursor: pointer !important; - width: 100% !important; } - .clearing-assembled .clearing-container .carousel > ul li.visible { - opacity: 1; } - .clearing-assembled .clearing-container .carousel > ul li:hover { - opacity: .8; } - .clearing-assembled .clearing-container .visible-img { - background: #333333; - height: 85%; - overflow: hidden; } - - .clearing-close { - padding-left: 0; - padding-top: 0; - position: absolute; - top: 10px; - right: 20px; } } -/* Foundation Dropdowns */ -.f-dropdown { - display: none; - left: -9999px; - list-style: none; - margin-left: 0; - position: absolute; - background: #FFFFFF; - border: solid 1px #cccccc; - font-size: 0.875rem; - height: auto; - max-height: none; - width: 100%; - z-index: 89; - margin-top: 2px; - max-width: 200px; } - .f-dropdown.open { - display: block; } - .f-dropdown > *:first-child { - margin-top: 0; } - .f-dropdown > *:last-child { - margin-bottom: 0; } - .f-dropdown:before { - border: inset 6px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent transparent #FFFFFF transparent; - border-bottom-style: solid; - position: absolute; - top: -12px; - left: 10px; - z-index: 89; } - .f-dropdown:after { - border: inset 7px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent transparent #cccccc transparent; - border-bottom-style: solid; - position: absolute; - top: -14px; - left: 9px; - z-index: 88; } - .f-dropdown.right:before { - left: auto; - right: 10px; } - .f-dropdown.right:after { - left: auto; - right: 9px; } - .f-dropdown.drop-right { - display: none; - left: -9999px; - list-style: none; - margin-left: 0; - position: absolute; - background: #FFFFFF; - border: solid 1px #cccccc; - font-size: 0.875rem; - height: auto; - max-height: none; - width: 100%; - z-index: 89; - margin-top: 0; - margin-left: 2px; - max-width: 200px; } - .f-dropdown.drop-right.open { - display: block; } - .f-dropdown.drop-right > *:first-child { - margin-top: 0; } - .f-dropdown.drop-right > *:last-child { - margin-bottom: 0; } - .f-dropdown.drop-right:before { - border: inset 6px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent #FFFFFF transparent transparent; - border-right-style: solid; - position: absolute; - top: 10px; - left: -12px; - z-index: 89; } - .f-dropdown.drop-right:after { - border: inset 7px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent #cccccc transparent transparent; - border-right-style: solid; - position: absolute; - top: 9px; - left: -14px; - z-index: 88; } - .f-dropdown.drop-left { - display: none; - left: -9999px; - list-style: none; - margin-left: 0; - position: absolute; - background: #FFFFFF; - border: solid 1px #cccccc; - font-size: 0.875rem; - height: auto; - max-height: none; - width: 100%; - z-index: 89; - margin-top: 0; - margin-left: -2px; - max-width: 200px; } - .f-dropdown.drop-left.open { - display: block; } - .f-dropdown.drop-left > *:first-child { - margin-top: 0; } - .f-dropdown.drop-left > *:last-child { - margin-bottom: 0; } - .f-dropdown.drop-left:before { - border: inset 6px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent transparent transparent #FFFFFF; - border-left-style: solid; - position: absolute; - top: 10px; - right: -12px; - left: auto; - z-index: 89; } - .f-dropdown.drop-left:after { - border: inset 7px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent transparent transparent #cccccc; - border-left-style: solid; - position: absolute; - top: 9px; - right: -14px; - left: auto; - z-index: 88; } - .f-dropdown.drop-top { - display: none; - left: -9999px; - list-style: none; - margin-left: 0; - position: absolute; - background: #FFFFFF; - border: solid 1px #cccccc; - font-size: 0.875rem; - height: auto; - max-height: none; - width: 100%; - z-index: 89; - margin-left: 0; - margin-top: -2px; - max-width: 200px; } - .f-dropdown.drop-top.open { - display: block; } - .f-dropdown.drop-top > *:first-child { - margin-top: 0; } - .f-dropdown.drop-top > *:last-child { - margin-bottom: 0; } - .f-dropdown.drop-top:before { - border: inset 6px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: #FFFFFF transparent transparent transparent; - border-top-style: solid; - bottom: -12px; - position: absolute; - top: auto; - left: 10px; - right: auto; - z-index: 89; } - .f-dropdown.drop-top:after { - border: inset 7px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: #cccccc transparent transparent transparent; - border-top-style: solid; - bottom: -14px; - position: absolute; - top: auto; - left: 9px; - right: auto; - z-index: 88; } - .f-dropdown li { - cursor: pointer; - font-size: 0.875rem; - line-height: 1.125rem; - margin: 0; } - .f-dropdown li:hover, .f-dropdown li:focus { - background: #EEEEEE; } - .f-dropdown li a { - display: block; - padding: 0.5rem; - color: #555555; } - .f-dropdown.content { - display: none; - left: -9999px; - list-style: none; - margin-left: 0; - position: absolute; - background: #FFFFFF; - border: solid 1px #cccccc; - font-size: 0.875rem; - height: auto; - max-height: none; - padding: 1.25rem; - width: 100%; - z-index: 89; - max-width: 200px; } - .f-dropdown.content.open { - display: block; } - .f-dropdown.content > *:first-child { - margin-top: 0; } - .f-dropdown.content > *:last-child { - margin-bottom: 0; } - .f-dropdown.radius { - border-radius: 3px; } - .f-dropdown.tiny { - max-width: 200px; } - .f-dropdown.small { - max-width: 300px; } - .f-dropdown.medium { - max-width: 500px; } - .f-dropdown.large { - max-width: 800px; } - .f-dropdown.mega { - width: 100% !important; - max-width: 100% !important; } - .f-dropdown.mega.open { - left: 0 !important; } - -.dropdown.button, button.dropdown { - position: relative; - padding-right: 3.5625rem; } - .dropdown.button::after, button.dropdown::after { - border-color: #FFFFFF transparent transparent transparent; - border-style: solid; - content: ""; - display: block; - height: 0; - position: absolute; - top: 50%; - width: 0; } - .dropdown.button::after, button.dropdown::after { - border-width: 0.375rem; - right: 1.40625rem; - margin-top: -0.15625rem; } - .dropdown.button::after, button.dropdown::after { - border-color: #FFFFFF transparent transparent transparent; } - .dropdown.button.tiny, button.dropdown.tiny { - padding-right: 2.625rem; } - .dropdown.button.tiny:after, button.dropdown.tiny:after { - border-width: 0.375rem; - right: 1.125rem; - margin-top: -0.125rem; } - .dropdown.button.tiny::after, button.dropdown.tiny::after { - border-color: #FFFFFF transparent transparent transparent; } - .dropdown.button.small, button.dropdown.small { - padding-right: 3.0625rem; } - .dropdown.button.small::after, button.dropdown.small::after { - border-width: 0.4375rem; - right: 1.3125rem; - margin-top: -0.15625rem; } - .dropdown.button.small::after, button.dropdown.small::after { - border-color: #FFFFFF transparent transparent transparent; } - .dropdown.button.large, button.dropdown.large { - padding-right: 3.625rem; } - .dropdown.button.large::after, button.dropdown.large::after { - border-width: 0.3125rem; - right: 1.71875rem; - margin-top: -0.15625rem; } - .dropdown.button.large::after, button.dropdown.large::after { - border-color: #FFFFFF transparent transparent transparent; } - .dropdown.button.secondary:after, button.dropdown.secondary:after { - border-color: #333333 transparent transparent transparent; } - -.flex-video { - height: 0; - margin-bottom: 1rem; - overflow: hidden; - padding-bottom: 67.5%; - padding-top: 1.5625rem; - position: relative; } - .flex-video.widescreen { - padding-bottom: 56.34%; } - .flex-video.vimeo { - padding-top: 0; } - .flex-video iframe, - .flex-video object, - .flex-video embed, - .flex-video video { - height: 100%; - position: absolute; - top: 0; - width: 100%; - left: 0; } - -/* Standard Forms */ -form { - margin: 0 0 1rem; } - -/* Using forms within rows, we need to set some defaults */ -form .row .row { - margin: 0 -0.5rem; } - form .row .row .column, - form .row .row .columns { - padding: 0 0.5rem; } - form .row .row.collapse { - margin: 0; } - form .row .row.collapse .column, - form .row .row.collapse .columns { - padding: 0; } - form .row .row.collapse input { - -webkit-border-bottom-right-radius: 0; - -webkit-border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-top-right-radius: 0; } -form .row input.column, -form .row input.columns, -form .row textarea.column, -form .row textarea.columns { - padding-left: 0.5rem; } - -/* Label Styles */ -label { - color: #4d4d4d; - cursor: pointer; - display: block; - font-size: 0.875rem; - font-weight: normal; - line-height: 1.5; - margin-bottom: 0; - /* Styles for required inputs */ } - label.right { - float: none !important; - text-align: right; } - label.inline { - margin: 0 0 1rem 0; - padding: 0.5625rem 0; } - label small { - text-transform: capitalize; - color: #676767; } - -/* Attach elements to the beginning or end of an input */ -.prefix, -.postfix { - border-style: solid; - border-width: 1px; - display: block; - font-size: 0.875rem; - height: 2.3125rem; - line-height: 2.3125rem; - overflow: visible; - padding-bottom: 0; - padding-top: 0; - position: relative; - text-align: center; - width: 100%; - z-index: 2; } - -/* Adjust padding, alignment and radius if pre/post element is a button */ -.postfix.button { - border: none; - padding-left: 0; - padding-right: 0; - padding-bottom: 0; - padding-top: 0; - text-align: center; } - -.prefix.button { - border: none; - padding-left: 0; - padding-right: 0; - padding-bottom: 0; - padding-top: 0; - text-align: center; } - -.prefix.button.radius { - border-radius: 0; - -webkit-border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; } - -.postfix.button.radius { - border-radius: 0; - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } - -.prefix.button.round { - border-radius: 0; - -webkit-border-bottom-left-radius: 1000px; - -webkit-border-top-left-radius: 1000px; - border-bottom-left-radius: 1000px; - border-top-left-radius: 1000px; } - -.postfix.button.round { - border-radius: 0; - -webkit-border-bottom-right-radius: 1000px; - -webkit-border-top-right-radius: 1000px; - border-bottom-right-radius: 1000px; - border-top-right-radius: 1000px; } - -/* Separate prefix and postfix styles when on span or label so buttons keep their own */ -span.prefix, label.prefix { - background: #f2f2f2; - border-right: none; - color: #333333; - border-color: #cccccc; } - -span.postfix, label.postfix { - background: #f2f2f2; - border-left: none; - color: #333333; - border-color: #cccccc; } - -/* We use this to get basic styling on all basic form elements */ -input:not([type]), input[type="text"], input[type="password"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="week"], input[type="email"], input[type="number"], input[type="search"], input[type="tel"], input[type="time"], input[type="url"], input[type="color"], textarea { - -webkit-appearance: none; - -moz-appearance: none; - border-radius: 0; - background-color: #FFFFFF; - border-style: solid; - border-width: 1px; - border-color: #cccccc; - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - color: rgba(0, 0, 0, 0.75); - display: block; - font-family: inherit; - font-size: 0.875rem; - height: 2.3125rem; - margin: 0 0 1rem 0; - padding: 0.5rem; - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - -webkit-transition: border-color 0.15s linear, background 0.15s linear; - -moz-transition: border-color 0.15s linear, background 0.15s linear; - -ms-transition: border-color 0.15s linear, background 0.15s linear; - -o-transition: border-color 0.15s linear, background 0.15s linear; - transition: border-color 0.15s linear, background 0.15s linear; } - input:not([type]):focus, input[type="text"]:focus, input[type="password"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="week"]:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="time"]:focus, input[type="url"]:focus, input[type="color"]:focus, textarea:focus { - background: #fafafa; - border-color: #999999; - outline: none; } - input:not([type]):disabled, input[type="text"]:disabled, input[type="password"]:disabled, input[type="date"]:disabled, input[type="datetime"]:disabled, input[type="datetime-local"]:disabled, input[type="month"]:disabled, input[type="week"]:disabled, input[type="email"]:disabled, input[type="number"]:disabled, input[type="search"]:disabled, input[type="tel"]:disabled, input[type="time"]:disabled, input[type="url"]:disabled, input[type="color"]:disabled, textarea:disabled { - background-color: #DDDDDD; - cursor: default; } - input:not([type])[disabled], input:not([type])[readonly], fieldset[disabled] input:not([type]), input[type="text"][disabled], input[type="text"][readonly], fieldset[disabled] input[type="text"], input[type="password"][disabled], input[type="password"][readonly], fieldset[disabled] input[type="password"], input[type="date"][disabled], input[type="date"][readonly], fieldset[disabled] input[type="date"], input[type="datetime"][disabled], input[type="datetime"][readonly], fieldset[disabled] input[type="datetime"], input[type="datetime-local"][disabled], input[type="datetime-local"][readonly], fieldset[disabled] input[type="datetime-local"], input[type="month"][disabled], input[type="month"][readonly], fieldset[disabled] input[type="month"], input[type="week"][disabled], input[type="week"][readonly], fieldset[disabled] input[type="week"], input[type="email"][disabled], input[type="email"][readonly], fieldset[disabled] input[type="email"], input[type="number"][disabled], input[type="number"][readonly], fieldset[disabled] input[type="number"], input[type="search"][disabled], input[type="search"][readonly], fieldset[disabled] input[type="search"], input[type="tel"][disabled], input[type="tel"][readonly], fieldset[disabled] input[type="tel"], input[type="time"][disabled], input[type="time"][readonly], fieldset[disabled] input[type="time"], input[type="url"][disabled], input[type="url"][readonly], fieldset[disabled] input[type="url"], input[type="color"][disabled], input[type="color"][readonly], fieldset[disabled] input[type="color"], textarea[disabled], textarea[readonly], fieldset[disabled] textarea { - background-color: #DDDDDD; - cursor: default; } - input:not([type]).radius, input[type="text"].radius, input[type="password"].radius, input[type="date"].radius, input[type="datetime"].radius, input[type="datetime-local"].radius, input[type="month"].radius, input[type="week"].radius, input[type="email"].radius, input[type="number"].radius, input[type="search"].radius, input[type="tel"].radius, input[type="time"].radius, input[type="url"].radius, input[type="color"].radius, textarea.radius { - border-radius: 3px; } - -form .row .prefix-radius.row.collapse input, -form .row .prefix-radius.row.collapse textarea, -form .row .prefix-radius.row.collapse select, -form .row .prefix-radius.row.collapse button { - border-radius: 0; - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } -form .row .prefix-radius.row.collapse .prefix { - border-radius: 0; - -webkit-border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; } -form .row .postfix-radius.row.collapse input, -form .row .postfix-radius.row.collapse textarea, -form .row .postfix-radius.row.collapse select, -form .row .postfix-radius.row.collapse button { - border-radius: 0; - -webkit-border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; } -form .row .postfix-radius.row.collapse .postfix { - border-radius: 0; - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } -form .row .prefix-round.row.collapse input, -form .row .prefix-round.row.collapse textarea, -form .row .prefix-round.row.collapse select, -form .row .prefix-round.row.collapse button { - border-radius: 0; - -webkit-border-bottom-right-radius: 1000px; - -webkit-border-top-right-radius: 1000px; - border-bottom-right-radius: 1000px; - border-top-right-radius: 1000px; } -form .row .prefix-round.row.collapse .prefix { - border-radius: 0; - -webkit-border-bottom-left-radius: 1000px; - -webkit-border-top-left-radius: 1000px; - border-bottom-left-radius: 1000px; - border-top-left-radius: 1000px; } -form .row .postfix-round.row.collapse input, -form .row .postfix-round.row.collapse textarea, -form .row .postfix-round.row.collapse select, -form .row .postfix-round.row.collapse button { - border-radius: 0; - -webkit-border-bottom-left-radius: 1000px; - -webkit-border-top-left-radius: 1000px; - border-bottom-left-radius: 1000px; - border-top-left-radius: 1000px; } -form .row .postfix-round.row.collapse .postfix { - border-radius: 0; - -webkit-border-bottom-right-radius: 1000px; - -webkit-border-top-right-radius: 1000px; - border-bottom-right-radius: 1000px; - border-top-right-radius: 1000px; } - -input[type="submit"] { - -webkit-appearance: none; - -moz-appearance: none; - border-radius: 0; } - -/* Respect enforced amount of rows for textarea */ -textarea[rows] { - height: auto; } - -/* Not allow resize out of parent */ -textarea { - max-width: 100%; } - -::-webkit-input-placeholder { - color: #666666; } - -:-moz-placeholder { - /* Firefox 18- */ - color: #666666; } - -::-moz-placeholder { - /* Firefox 19+ */ - color: #666666; } - -:-ms-input-placeholder { - color: #666666; } - -/* Add height value for select elements to match text input height */ -select { - -webkit-appearance: none !important; - -moz-appearance: none !important; - background-color: #FAFAFA; - border-radius: 0; - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgeD0iMTJweCIgeT0iMHB4IiB3aWR0aD0iMjRweCIgaGVpZ2h0PSIzcHgiIHZpZXdCb3g9IjAgMCA2IDMiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDYgMyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBvbHlnb24gcG9pbnRzPSI1Ljk5MiwwIDIuOTkyLDMgLTAuMDA4LDAgIi8+PC9zdmc+"); - background-position: 100% center; - background-repeat: no-repeat; - border-style: solid; - border-width: 1px; - border-color: #cccccc; - color: rgba(0, 0, 0, 0.75); - font-family: inherit; - font-size: 0.875rem; - line-height: normal; - padding: 0.5rem; - border-radius: 0; - height: 2.3125rem; } - select::-ms-expand { - display: none; } - select.radius { - border-radius: 3px; } - select:focus { - background-color: #f3f3f3; - border-color: #999999; } - select:disabled { - background-color: #DDDDDD; - cursor: default; } - select[multiple] { - height: auto; } - -/* Adjust margin for form elements below */ -input[type="file"], -input[type="checkbox"], -input[type="radio"], -select { - margin: 0 0 1rem 0; } - -input[type="checkbox"] + label, -input[type="radio"] + label { - display: inline-block; - margin-left: 0.5rem; - margin-right: 1rem; - margin-bottom: 0; - vertical-align: baseline; } - -/* Normalize file input width */ -input[type="file"] { - width: 100%; } - -/* HTML5 Number spinners settings */ -/* We add basic fieldset styling */ -fieldset { - border: 1px solid #DDDDDD; - margin: 1.125rem 0; - padding: 1.25rem; } - fieldset legend { - font-weight: bold; - margin: 0; - margin-left: -0.1875rem; - padding: 0 0.1875rem; } - -/* Error Handling */ -[data-abide] .error small.error, [data-abide] .error span.error, [data-abide] span.error, [data-abide] small.error { - display: block; - font-size: 0.75rem; - font-style: italic; - font-weight: normal; - margin-bottom: 1rem; - margin-top: -1px; - padding: 0.375rem 0.5625rem 0.5625rem; - background: #f04124; - color: #FFFFFF; } -[data-abide] span.error, [data-abide] small.error { - display: none; } - -span.error, small.error { - display: block; - font-size: 0.75rem; - font-style: italic; - font-weight: normal; - margin-bottom: 1rem; - margin-top: -1px; - padding: 0.375rem 0.5625rem 0.5625rem; - background: #f04124; - color: #FFFFFF; } - -.error input, -.error textarea, -.error select { - margin-bottom: 0; } -.error input[type="checkbox"], -.error input[type="radio"] { - margin-bottom: 1rem; } -.error label, -.error label.error { - color: #f04124; } -.error small.error { - display: block; - font-size: 0.75rem; - font-style: italic; - font-weight: normal; - margin-bottom: 1rem; - margin-top: -1px; - padding: 0.375rem 0.5625rem 0.5625rem; - background: #f04124; - color: #FFFFFF; } -.error > label > small { - background: transparent; - color: #676767; - display: inline; - font-size: 60%; - font-style: normal; - margin: 0; - padding: 0; - text-transform: capitalize; } -.error span.error-message { - display: block; } - -input.error, -textarea.error, -select.error { - margin-bottom: 0; } - -label.error { - color: #f04124; } - -.icon-bar { - display: inline-block; - font-size: 0; - width: 100%; - background: #333333; } - .icon-bar > * { - display: block; - float: left; - font-size: 1rem; - margin: 0 auto; - padding: 1.25rem; - text-align: center; - width: 25%; } - .icon-bar > * i, .icon-bar > * img { - display: block; - margin: 0 auto; } - .icon-bar > * i + label, .icon-bar > * img + label { - margin-top: .0625rem; } - .icon-bar > * i { - font-size: 1.875rem; - vertical-align: middle; } - .icon-bar > * img { - height: 1.875rem; - width: 1.875rem; } - .icon-bar.label-right > * i, .icon-bar.label-right > * img { - display: inline-block; - margin: 0 .0625rem 0 0; } - .icon-bar.label-right > * i + label, .icon-bar.label-right > * img + label { - margin-top: 0; } - .icon-bar.label-right > * label { - display: inline-block; } - .icon-bar.vertical.label-right > * { - text-align: left; } - .icon-bar.vertical, .icon-bar.small-vertical { - height: 100%; - width: auto; } - .icon-bar.vertical .item, .icon-bar.small-vertical .item { - float: none; - margin: auto; - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.medium-vertical { - height: 100%; - width: auto; } - .icon-bar.medium-vertical .item { - float: none; - margin: auto; - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.large-vertical { - height: 100%; - width: auto; } - .icon-bar.large-vertical .item { - float: none; - margin: auto; - width: auto; } } - .icon-bar > * { - font-size: 1rem; - padding: 1.25rem; } - .icon-bar > * i + label, .icon-bar > * img + label { - margin-top: .0625rem; - font-size: 1rem; } - .icon-bar > * i { - font-size: 1.875rem; } - .icon-bar > * img { - height: 1.875rem; - width: 1.875rem; } - .icon-bar > * label { - color: #FFFFFF; } - .icon-bar > * i { - color: #FFFFFF; } - .icon-bar > a:hover { - background: #008CBA; } - .icon-bar > a:hover label { - color: #FFFFFF; } - .icon-bar > a:hover i { - color: #FFFFFF; } - .icon-bar > a.active { - background: #008CBA; } - .icon-bar > a.active label { - color: #FFFFFF; } - .icon-bar > a.active i { - color: #FFFFFF; } - .icon-bar .item.disabled { - cursor: not-allowed; - opacity: 0.7; - pointer-events: none; } - .icon-bar .item.disabled > * { - opacity: 0.7; - cursor: not-allowed; } - .icon-bar.two-up .item { - width: 50%; } - .icon-bar.two-up.vertical .item, .icon-bar.two-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.two-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.two-up.large-vertical .item { - width: auto; } } - .icon-bar.three-up .item { - width: 33.3333%; } - .icon-bar.three-up.vertical .item, .icon-bar.three-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.three-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.three-up.large-vertical .item { - width: auto; } } - .icon-bar.four-up .item { - width: 25%; } - .icon-bar.four-up.vertical .item, .icon-bar.four-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.four-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.four-up.large-vertical .item { - width: auto; } } - .icon-bar.five-up .item { - width: 20%; } - .icon-bar.five-up.vertical .item, .icon-bar.five-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.five-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.five-up.large-vertical .item { - width: auto; } } - .icon-bar.six-up .item { - width: 16.66667%; } - .icon-bar.six-up.vertical .item, .icon-bar.six-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.six-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.six-up.large-vertical .item { - width: auto; } } - .icon-bar.seven-up .item { - width: 14.28571%; } - .icon-bar.seven-up.vertical .item, .icon-bar.seven-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.seven-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.seven-up.large-vertical .item { - width: auto; } } - .icon-bar.eight-up .item { - width: 12.5%; } - .icon-bar.eight-up.vertical .item, .icon-bar.eight-up.small-vertical .item { - width: auto; } - @media only screen and (min-width: 40.0625em) { - .icon-bar.eight-up.medium-vertical .item { - width: auto; } } - @media only screen and (min-width: 64.0625em) { - .icon-bar.eight-up.large-vertical .item { - width: auto; } } - -.icon-bar.two-up .item { - width: 50%; } -.icon-bar.two-up.vertical .item, .icon-bar.two-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.two-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.two-up.large-vertical .item { - width: auto; } } -.icon-bar.three-up .item { - width: 33.3333%; } -.icon-bar.three-up.vertical .item, .icon-bar.three-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.three-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.three-up.large-vertical .item { - width: auto; } } -.icon-bar.four-up .item { - width: 25%; } -.icon-bar.four-up.vertical .item, .icon-bar.four-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.four-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.four-up.large-vertical .item { - width: auto; } } -.icon-bar.five-up .item { - width: 20%; } -.icon-bar.five-up.vertical .item, .icon-bar.five-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.five-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.five-up.large-vertical .item { - width: auto; } } -.icon-bar.six-up .item { - width: 16.66667%; } -.icon-bar.six-up.vertical .item, .icon-bar.six-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.six-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.six-up.large-vertical .item { - width: auto; } } -.icon-bar.seven-up .item { - width: 14.28571%; } -.icon-bar.seven-up.vertical .item, .icon-bar.seven-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.seven-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.seven-up.large-vertical .item { - width: auto; } } -.icon-bar.eight-up .item { - width: 12.5%; } -.icon-bar.eight-up.vertical .item, .icon-bar.eight-up.small-vertical .item { - width: auto; } -@media only screen and (min-width: 40.0625em) { - .icon-bar.eight-up.medium-vertical .item { - width: auto; } } -@media only screen and (min-width: 64.0625em) { - .icon-bar.eight-up.large-vertical .item { - width: auto; } } - -.inline-list { - list-style: none; - margin-top: 0; - margin-bottom: 1.0625rem; - margin-left: -1.375rem; - margin-right: 0; - overflow: hidden; - padding: 0; } - .inline-list > li { - display: block; - float: left; - list-style: none; - margin-left: 1.375rem; } - .inline-list > li > * { - display: block; } - -/* Foundation Joyride */ -.joyride-list { - display: none; } - -/* Default styles for the container */ -.joyride-tip-guide { - background: #333333; - color: #FFFFFF; - display: none; - font-family: inherit; - font-weight: normal; - position: absolute; - top: 0; - width: 95%; - z-index: 103; - left: 2.5%; } - -.lt-ie9 .joyride-tip-guide { - margin-left: -400px; - max-width: 800px; - left: 50%; } - -.joyride-content-wrapper { - padding: 1.125rem 1.25rem 1.5rem; - width: 100%; } - .joyride-content-wrapper .button { - margin-bottom: 0 !important; } - .joyride-content-wrapper .joyride-prev-tip { - margin-right: 10px; } - -/* Add a little css triangle pip, older browser just miss out on the fanciness of it */ -.joyride-tip-guide .joyride-nub { - border: 10px solid #333333; - display: block; - height: 0; - position: absolute; - width: 0; - left: 22px; } - .joyride-tip-guide .joyride-nub.top { - border-color: #333333; - border-top-color: transparent !important; - border-top-style: solid; - border-left-color: transparent !important; - border-right-color: transparent !important; - top: -20px; } - .joyride-tip-guide .joyride-nub.bottom { - border-color: #333333 !important; - border-bottom-color: transparent !important; - border-bottom-style: solid; - border-left-color: transparent !important; - border-right-color: transparent !important; - bottom: -20px; } - .joyride-tip-guide .joyride-nub.right { - right: -20px; } - .joyride-tip-guide .joyride-nub.left { - left: -20px; } - -/* Typography */ -.joyride-tip-guide h1, -.joyride-tip-guide h2, -.joyride-tip-guide h3, -.joyride-tip-guide h4, -.joyride-tip-guide h5, -.joyride-tip-guide h6 { - color: #FFFFFF; - font-weight: bold; - line-height: 1.25; - margin: 0; } - -.joyride-tip-guide p { - font-size: 0.875rem; - line-height: 1.3; - margin: 0 0 1.125rem 0; } - -.joyride-timer-indicator-wrap { - border: solid 1px #555555; - bottom: 1rem; - height: 3px; - position: absolute; - width: 50px; - right: 1.0625rem; } - -.joyride-timer-indicator { - background: #666666; - display: block; - height: inherit; - width: 0; } - -.joyride-close-tip { - color: #777777 !important; - font-size: 24px; - font-weight: normal; - line-height: .5 !important; - position: absolute; - text-decoration: none; - top: 10px; - right: 12px; } - .joyride-close-tip:hover, .joyride-close-tip:focus { - color: #EEEEEE !important; } - -.joyride-modal-bg { - background: rgba(0, 0, 0, 0.5); - cursor: pointer; - display: none; - height: 100%; - position: fixed; - top: 0; - width: 100%; - z-index: 100; - left: 0; } - -.joyride-expose-wrapper { - background-color: #FFFFFF; - border-radius: 3px; - box-shadow: 0 0 15px #FFFFFF; - position: absolute; - z-index: 102; } - -.joyride-expose-cover { - background: transparent; - border-radius: 3px; - left: 0; - position: absolute; - top: 0; - z-index: 9999; } - -/* Styles for screens that are at least 768px; */ -@media only screen { - .joyride-tip-guide { - width: 300px; - left: inherit; } - .joyride-tip-guide .joyride-nub.bottom { - border-color: #333333 !important; - border-bottom-color: transparent !important; - border-left-color: transparent !important; - border-right-color: transparent !important; - bottom: -20px; } - .joyride-tip-guide .joyride-nub.right { - border-color: #333333 !important; - border-right-color: transparent !important; - border-bottom-color: transparent !important; - border-top-color: transparent !important; - left: auto; - right: -20px; - top: 22px; } - .joyride-tip-guide .joyride-nub.left { - border-color: #333333 !important; - border-bottom-color: transparent !important; - border-left-color: transparent !important; - border-top-color: transparent !important; - left: -20px; - right: auto; - top: 22px; } } -.keystroke, -kbd { - background-color: #ededed; - border-color: #dddddd; - color: #222222; - border-style: solid; - border-width: 1px; - font-family: "Consolas", "Menlo", "Courier", monospace; - font-size: inherit; - margin: 0; - padding: 0.125rem 0.25rem 0; - border-radius: 3px; } - -.label { - display: inline-block; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-weight: normal; - line-height: 1; - margin-bottom: auto; - position: relative; - text-align: center; - text-decoration: none; - white-space: nowrap; - padding: 0.25rem 0.5rem 0.25rem; - font-size: 0.6875rem; - background-color: #008CBA; - color: #FFFFFF; } - .label.radius { - border-radius: 3px; } - .label.round { - border-radius: 1000px; } - .label.alert { - background-color: #f04124; - color: #FFFFFF; } - .label.warning { - background-color: #f08a24; - color: #FFFFFF; } - .label.success { - background-color: #43AC6A; - color: #FFFFFF; } - .label.secondary { - background-color: #e7e7e7; - color: #333333; } - .label.info { - background-color: #a0d3e8; - color: #333333; } - -[data-magellan-expedition], [data-magellan-expedition-clone] { - background: #FFFFFF; - min-width: 100%; - padding: 10px; - z-index: 50; } - [data-magellan-expedition] .sub-nav, [data-magellan-expedition-clone] .sub-nav { - margin-bottom: 0; } - [data-magellan-expedition] .sub-nav dd, [data-magellan-expedition-clone] .sub-nav dd { - margin-bottom: 0; } - [data-magellan-expedition] .sub-nav a, [data-magellan-expedition-clone] .sub-nav a { - line-height: 1.8em; } - -@-webkit-keyframes rotate { - from { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); } - to { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); } } -@keyframes rotate { - from { - -webkit-transform: rotate(0deg); - -moz-transform: rotate(0deg); - -ms-transform: rotate(0deg); - transform: rotate(0deg); } - to { - -webkit-transform: rotate(360deg); - -moz-transform: rotate(360deg); - -ms-transform: rotate(360deg); - transform: rotate(360deg); } } -/* Orbit Graceful Loading */ -.slideshow-wrapper { - position: relative; } - .slideshow-wrapper ul { - list-style-type: none; - margin: 0; } - .slideshow-wrapper ul li, - .slideshow-wrapper ul li .orbit-caption { - display: none; } - .slideshow-wrapper ul li:first-child { - display: block; } - .slideshow-wrapper .orbit-container { - background-color: transparent; } - .slideshow-wrapper .orbit-container li { - display: block; } - .slideshow-wrapper .orbit-container li .orbit-caption { - display: block; } - .slideshow-wrapper .orbit-container .orbit-bullets li { - display: inline-block; } - .slideshow-wrapper .preloader { - border-radius: 1000px; - animation-duration: 1.5s; - animation-iteration-count: infinite; - animation-name: rotate; - animation-timing-function: linear; - border-color: #555555 #FFFFFF; - border: solid 3px; - display: block; - height: 40px; - left: 50%; - margin-left: -20px; - margin-top: -20px; - position: absolute; - top: 50%; - width: 40px; } - -.orbit-container { - background: none; - overflow: hidden; - position: relative; - width: 100%; } - .orbit-container .orbit-slides-container { - list-style: none; - margin: 0; - padding: 0; - position: relative; - -webkit-transform: translateZ(0); - -moz-transform: translateZ(0); - -ms-transform: translateZ(0); - -o-transform: translateZ(0); - transform: translateZ(0); } - .orbit-container .orbit-slides-container img { - display: block; - max-width: 100%; } - .orbit-container .orbit-slides-container > * { - position: absolute; - top: 0; - width: 100%; - margin-left: 100%; } - .orbit-container .orbit-slides-container > *:first-child { - margin-left: 0; } - .orbit-container .orbit-slides-container > * .orbit-caption { - bottom: 0; - position: absolute; - background-color: rgba(51, 51, 51, 0.8); - color: #FFFFFF; - font-size: 0.875rem; - padding: 0.625rem 0.875rem; - width: 100%; } - .orbit-container .orbit-slide-number { - left: 10px; - background: transparent; - color: #FFFFFF; - font-size: 12px; - position: absolute; - top: 10px; - z-index: 10; } - .orbit-container .orbit-slide-number span { - font-weight: 700; - padding: 0.3125rem; } - .orbit-container .orbit-timer { - position: absolute; - top: 12px; - right: 10px; - height: 6px; - width: 100px; - z-index: 10; } - .orbit-container .orbit-timer .orbit-progress { - height: 3px; - background-color: rgba(255, 255, 255, 0.3); - display: block; - width: 0; - position: relative; - right: 20px; - top: 5px; } - .orbit-container .orbit-timer > span { - border: solid 4px #FFFFFF; - border-bottom: none; - border-top: none; - display: none; - height: 14px; - position: absolute; - top: 0; - width: 11px; - right: 0; } - .orbit-container .orbit-timer.paused > span { - top: 0; - width: 11px; - height: 14px; - border: inset 8px; - border-left-style: solid; - border-color: transparent; - border-left-color: #FFFFFF; - right: -4px; } - .orbit-container .orbit-timer.paused > span.dark { - border-left-color: #333333; } - .orbit-container:hover .orbit-timer > span { - display: block; } - .orbit-container .orbit-prev, - .orbit-container .orbit-next { - background-color: transparent; - color: white; - height: 60px; - line-height: 50px; - margin-top: -25px; - position: absolute; - text-indent: -9999px !important; - top: 45%; - width: 36px; - z-index: 10; } - .orbit-container .orbit-prev:hover, - .orbit-container .orbit-next:hover { - background-color: rgba(0, 0, 0, 0.3); } - .orbit-container .orbit-prev > span, - .orbit-container .orbit-next > span { - border: inset 10px; - display: block; - height: 0; - margin-top: -10px; - position: absolute; - top: 50%; - width: 0; } - .orbit-container .orbit-prev { - left: 0; } - .orbit-container .orbit-prev > span { - border-right-style: solid; - border-color: transparent; - border-right-color: #FFFFFF; } - .orbit-container .orbit-prev:hover > span { - border-right-color: #FFFFFF; } - .orbit-container .orbit-next { - right: 0; } - .orbit-container .orbit-next > span { - border-color: transparent; - border-left-style: solid; - border-left-color: #FFFFFF; - left: 50%; - margin-left: -4px; } - .orbit-container .orbit-next:hover > span { - border-left-color: #FFFFFF; } - -.orbit-bullets-container { - text-align: center; } - -.orbit-bullets { - display: block; - float: none; - margin: 0 auto 30px auto; - overflow: hidden; - position: relative; - text-align: center; - top: 10px; } - .orbit-bullets li { - background: #CCCCCC; - cursor: pointer; - display: inline-block; - float: none; - height: 0.5625rem; - margin-right: 6px; - width: 0.5625rem; - border-radius: 1000px; } - .orbit-bullets li.active { - background: #999999; } - .orbit-bullets li:last-child { - margin-right: 0; } - -.touch .orbit-container .orbit-prev, -.touch .orbit-container .orbit-next { - display: none; } -.touch .orbit-bullets { - display: none; } - -@media only screen and (min-width: 40.0625em) { - .touch .orbit-container .orbit-prev, - .touch .orbit-container .orbit-next { - display: inherit; } - .touch .orbit-bullets { - display: block; } } -@media only screen and (max-width: 40em) { - .orbit-stack-on-small .orbit-slides-container { - height: auto !important; } - .orbit-stack-on-small .orbit-slides-container > * { - margin: 0 !important; - opacity: 1 !important; - position: relative; } - .orbit-stack-on-small .orbit-slide-number { - display: none; } - - .orbit-timer { - display: none; } - - .orbit-next, .orbit-prev { - display: none; } - - .orbit-bullets { - display: none; } } -ul.pagination { - display: block; - margin-left: -0.3125rem; - min-height: 1.5rem; } - ul.pagination li { - color: #222222; - font-size: 0.875rem; - height: 1.5rem; - margin-left: 0.3125rem; } - ul.pagination li a, ul.pagination li button { - border-radius: 3px; - transition: background-color 300ms ease-out; - background: none; - color: #999999; - display: block; - font-size: 1em; - font-weight: normal; - line-height: inherit; - padding: 0.0625rem 0.625rem 0.0625rem; } - ul.pagination li:hover a, - ul.pagination li a:focus, ul.pagination li:hover button, - ul.pagination li button:focus { - background: #e6e6e6; } - ul.pagination li.unavailable a, ul.pagination li.unavailable button { - cursor: default; - color: #999999; - pointer-events: none; } - ul.pagination li.unavailable:hover a, ul.pagination li.unavailable a:focus, ul.pagination li.unavailable:hover button, ul.pagination li.unavailable button:focus { - background: transparent; } - ul.pagination li.current a, ul.pagination li.current button { - background: #008CBA; - color: #FFFFFF; - cursor: default; - font-weight: bold; } - ul.pagination li.current a:hover, ul.pagination li.current a:focus, ul.pagination li.current button:hover, ul.pagination li.current button:focus { - background: #008CBA; } - ul.pagination li { - display: block; - float: left; } - -/* Pagination centred wrapper */ -.pagination-centered { - text-align: center; } - .pagination-centered ul.pagination li { - display: inline-block; - float: none; } - -/* Panels */ -.panel { - border-style: solid; - border-width: 1px; - border-color: #d8d8d8; - margin-bottom: 1.25rem; - padding: 1.25rem; - background: #f2f2f2; - color: #333333; } - .panel > :first-child { - margin-top: 0; } - .panel > :last-child { - margin-bottom: 0; } - .panel h1, .panel h2, .panel h3, .panel h4, .panel h5, .panel h6, .panel p, .panel li, .panel dl { - color: #333333; } - .panel h1, .panel h2, .panel h3, .panel h4, .panel h5, .panel h6 { - line-height: 1; - margin-bottom: 0.625rem; } - .panel h1.subheader, .panel h2.subheader, .panel h3.subheader, .panel h4.subheader, .panel h5.subheader, .panel h6.subheader { - line-height: 1.4; } - .panel.callout { - border-style: solid; - border-width: 1px; - border-color: #d8d8d8; - margin-bottom: 1.25rem; - padding: 1.25rem; - background: #ecfaff; - color: #333333; } - .panel.callout > :first-child { - margin-top: 0; } - .panel.callout > :last-child { - margin-bottom: 0; } - .panel.callout h1, .panel.callout h2, .panel.callout h3, .panel.callout h4, .panel.callout h5, .panel.callout h6, .panel.callout p, .panel.callout li, .panel.callout dl { - color: #333333; } - .panel.callout h1, .panel.callout h2, .panel.callout h3, .panel.callout h4, .panel.callout h5, .panel.callout h6 { - line-height: 1; - margin-bottom: 0.625rem; } - .panel.callout h1.subheader, .panel.callout h2.subheader, .panel.callout h3.subheader, .panel.callout h4.subheader, .panel.callout h5.subheader, .panel.callout h6.subheader { - line-height: 1.4; } - .panel.callout a:not(.button) { - color: #008CBA; } - .panel.callout a:not(.button):hover, .panel.callout a:not(.button):focus { - color: #0078a0; } - .panel.radius { - border-radius: 3px; } - -/* Pricing Tables */ -.pricing-table { - border: solid 1px #DDDDDD; - margin-left: 0; - margin-bottom: 1.25rem; } - .pricing-table * { - list-style: none; - line-height: 1; } - .pricing-table .title { - background-color: #333333; - color: #EEEEEE; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-size: 1rem; - font-weight: normal; - padding: 0.9375rem 1.25rem; - text-align: center; } - .pricing-table .price { - background-color: #F6F6F6; - color: #333333; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-size: 2rem; - font-weight: normal; - padding: 0.9375rem 1.25rem; - text-align: center; } - .pricing-table .description { - background-color: #FFFFFF; - border-bottom: dotted 1px #DDDDDD; - color: #777777; - font-size: 0.75rem; - font-weight: normal; - line-height: 1.4; - padding: 0.9375rem; - text-align: center; } - .pricing-table .bullet-item { - background-color: #FFFFFF; - border-bottom: dotted 1px #DDDDDD; - color: #333333; - font-size: 0.875rem; - font-weight: normal; - padding: 0.9375rem; - text-align: center; } - .pricing-table .cta-button { - background-color: #FFFFFF; - padding: 1.25rem 1.25rem 0; - text-align: center; } - -/* Progress Bar */ -.progress { - background-color: #F6F6F6; - border: 1px solid white; - height: 1.5625rem; - margin-bottom: 0.625rem; - padding: 0.125rem; } - .progress .meter { - background: #008CBA; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress .meter.secondary { - background: #e7e7e7; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress .meter.success { - background: #43AC6A; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress .meter.alert { - background: #f04124; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress.secondary .meter { - background: #e7e7e7; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress.success .meter { - background: #43AC6A; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress.alert .meter { - background: #f04124; - display: block; - height: 100%; - float: left; - width: 0%; } - .progress.radius { - border-radius: 3px; } - .progress.radius .meter { - border-radius: 2px; } - .progress.round { - border-radius: 1000px; } - .progress.round .meter { - border-radius: 999px; } - -.range-slider { - border: 1px solid #DDDDDD; - margin: 1.25rem 0; - position: relative; - -ms-touch-action: none; - touch-action: none; - display: block; - height: 1rem; - width: 100%; - background: #FAFAFA; } - .range-slider.vertical-range { - border: 1px solid #DDDDDD; - margin: 1.25rem 0; - position: relative; - -ms-touch-action: none; - touch-action: none; - display: inline-block; - height: 12.5rem; - width: 1rem; } - .range-slider.vertical-range .range-slider-handle { - bottom: -10.5rem; - margin-left: -0.5rem; - margin-top: 0; - position: absolute; } - .range-slider.vertical-range .range-slider-active-segment { - border-bottom-left-radius: inherit; - border-bottom-right-radius: inherit; - border-top-left-radius: initial; - bottom: 0; - height: auto; - width: 0.875rem; } - .range-slider.radius { - background: #FAFAFA; - border-radius: 3px; } - .range-slider.radius .range-slider-handle { - background: #008CBA; - border-radius: 3px; } - .range-slider.radius .range-slider-handle:hover { - background: #007ba4; } - .range-slider.round { - background: #FAFAFA; - border-radius: 1000px; } - .range-slider.round .range-slider-handle { - background: #008CBA; - border-radius: 1000px; } - .range-slider.round .range-slider-handle:hover { - background: #007ba4; } - .range-slider.disabled, .range-slider[disabled] { - background: #FAFAFA; - cursor: not-allowed; - opacity: 0.7; } - .range-slider.disabled .range-slider-handle, .range-slider[disabled] .range-slider-handle { - background: #008CBA; - cursor: default; - opacity: 0.7; } - .range-slider.disabled .range-slider-handle:hover, .range-slider[disabled] .range-slider-handle:hover { - background: #007ba4; } - -.range-slider-active-segment { - background: #e5e5e5; - border-bottom-left-radius: inherit; - border-top-left-radius: inherit; - display: inline-block; - height: 0.875rem; - position: absolute; } - -.range-slider-handle { - border: 1px solid none; - cursor: pointer; - display: inline-block; - height: 1.375rem; - position: absolute; - top: -0.3125rem; - width: 2rem; - z-index: 1; - -ms-touch-action: manipulation; - touch-action: manipulation; - background: #008CBA; } - .range-slider-handle:hover { - background: #007ba4; } - -.reveal-modal-bg { - background: #000000; - background: rgba(0, 0, 0, 0.45); - bottom: 0; - display: none; - left: 0; - position: fixed; - right: 0; - top: 0; - z-index: 1004; - left: 0; } - -.reveal-modal { - border-radius: 3px; - display: none; - position: absolute; - top: 0; - visibility: hidden; - width: 100%; - z-index: 1005; - left: 0; - background-color: #FFFFFF; - padding: 1.875rem; - border: solid 1px #666666; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.4); } - @media only screen and (max-width: 40em) { - .reveal-modal { - min-height: 100vh; } } - .reveal-modal .column, .reveal-modal .columns { - min-width: 0; } - .reveal-modal > :first-child { - margin-top: 0; } - .reveal-modal > :last-child { - margin-bottom: 0; } - @media only screen and (min-width: 40.0625em) { - .reveal-modal { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 80%; } } - @media only screen and (min-width: 40.0625em) { - .reveal-modal { - top: 6.25rem; } } - .reveal-modal.radius { - box-shadow: none; - border-radius: 3px; } - .reveal-modal.round { - box-shadow: none; - border-radius: 1000px; } - .reveal-modal.collapse { - padding: 0; - box-shadow: none; } - @media only screen and (min-width: 40.0625em) { - .reveal-modal.tiny { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 30%; } } - @media only screen and (min-width: 40.0625em) { - .reveal-modal.small { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 40%; } } - @media only screen and (min-width: 40.0625em) { - .reveal-modal.medium { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 60%; } } - @media only screen and (min-width: 40.0625em) { - .reveal-modal.large { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 70%; } } - @media only screen and (min-width: 40.0625em) { - .reveal-modal.xlarge { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 95%; } } - .reveal-modal.full { - height: 100vh; - height: 100%; - left: 0; - margin-left: 0 !important; - max-width: none !important; - min-height: 100vh; - top: 0; } - @media only screen and (min-width: 40.0625em) { - .reveal-modal.full { - left: 0; - margin: 0 auto; - max-width: 62.5rem; - right: 0; - width: 100%; } } - .reveal-modal.toback { - z-index: 1003; } - .reveal-modal .close-reveal-modal { - color: #AAAAAA; - cursor: pointer; - font-size: 2.5rem; - font-weight: bold; - line-height: 1; - position: absolute; - top: 0.625rem; - right: 1.375rem; } - -.side-nav { - display: block; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - list-style-position: outside; - list-style-type: none; - margin: 0; - padding: 0.875rem 0; } - .side-nav li { - font-size: 0.875rem; - font-weight: normal; - margin: 0 0 0.4375rem 0; } - .side-nav li a:not(.button) { - color: #008CBA; - display: block; - margin: 0; - padding: 0.4375rem 0.875rem; } - .side-nav li a:not(.button):hover, .side-nav li a:not(.button):focus { - background: rgba(0, 0, 0, 0.025); - color: #1cc7ff; } - .side-nav li a:not(.button):active { - color: #1cc7ff; } - .side-nav li.active > a:first-child:not(.button) { - color: #1cc7ff; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-weight: normal; } - .side-nav li.divider { - border-top: 1px solid; - height: 0; - list-style: none; - padding: 0; - border-top-color: #e6e6e6; } - .side-nav li.heading { - color: #008CBA; - font-size: 0.875rem; - font-weight: bold; - text-transform: uppercase; } - -.split.button { - position: relative; - padding-right: 5.0625rem; } - .split.button span { - display: block; - height: 100%; - position: absolute; - right: 0; - top: 0; - border-left: solid 1px; } - .split.button span:after { - position: absolute; - content: ""; - width: 0; - height: 0; - display: block; - border-style: inset; - top: 50%; - left: 50%; } - .split.button span:active { - background-color: rgba(0, 0, 0, 0.1); } - .split.button span { - border-left-color: rgba(255, 255, 255, 0.5); } - .split.button span { - width: 3.09375rem; } - .split.button span:after { - border-top-style: solid; - border-width: 0.375rem; - margin-left: -0.375rem; - top: 48%; } - .split.button span:after { - border-color: #FFFFFF transparent transparent transparent; } - .split.button.secondary span { - border-left-color: rgba(255, 255, 255, 0.5); } - .split.button.secondary span:after { - border-color: #FFFFFF transparent transparent transparent; } - .split.button.alert span { - border-left-color: rgba(255, 255, 255, 0.5); } - .split.button.success span { - border-left-color: rgba(255, 255, 255, 0.5); } - .split.button.tiny { - padding-right: 3.75rem; } - .split.button.tiny span { - width: 2.25rem; } - .split.button.tiny span:after { - border-top-style: solid; - border-width: 0.375rem; - margin-left: -0.375rem; - top: 48%; } - .split.button.small { - padding-right: 4.375rem; } - .split.button.small span { - width: 2.625rem; } - .split.button.small span:after { - border-top-style: solid; - border-width: 0.4375rem; - margin-left: -0.375rem; - top: 48%; } - .split.button.large { - padding-right: 5.5rem; } - .split.button.large span { - width: 3.4375rem; } - .split.button.large span:after { - border-top-style: solid; - border-width: 0.3125rem; - margin-left: -0.375rem; - top: 48%; } - .split.button.expand { - padding-left: 2rem; } - .split.button.secondary span:after { - border-color: #333333 transparent transparent transparent; } - .split.button.radius span { - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } - .split.button.round span { - -webkit-border-bottom-right-radius: 1000px; - -webkit-border-top-right-radius: 1000px; - border-bottom-right-radius: 1000px; - border-top-right-radius: 1000px; } - .split.button.no-pip span:before { - border-style: none; } - .split.button.no-pip span:after { - border-style: none; } - .split.button.no-pip span > i { - display: block; - left: 50%; - margin-left: -0.28889em; - margin-top: -0.48889em; - position: absolute; - top: 50%; } - -.sub-nav { - display: block; - margin: -0.25rem 0 1.125rem; - overflow: hidden; - padding-top: 0.25rem; - width: auto; } - .sub-nav dt { - text-transform: uppercase; } - .sub-nav dt, - .sub-nav dd, - .sub-nav li { - color: #999999; - float: left; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-size: 0.875rem; - font-weight: normal; - margin-left: 1rem; - margin-bottom: 0; } - .sub-nav dt a, - .sub-nav dd a, - .sub-nav li a { - color: #999999; - padding: 0.1875rem 1rem; - text-decoration: none; } - .sub-nav dt a:hover, - .sub-nav dd a:hover, - .sub-nav li a:hover { - color: #737373; } - .sub-nav dt.active a, - .sub-nav dd.active a, - .sub-nav li.active a { - border-radius: 3px; - background: #008CBA; - color: #FFFFFF; - cursor: default; - font-weight: normal; - padding: 0.1875rem 1rem; } - .sub-nav dt.active a:hover, - .sub-nav dd.active a:hover, - .sub-nav li.active a:hover { - background: #0078a0; } - -.switch { - border: none; - margin-bottom: 1.5rem; - outline: 0; - padding: 0; - position: relative; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; } - .switch label { - background: #DDDDDD; - color: transparent; - cursor: pointer; - display: block; - margin-bottom: 1rem; - position: relative; - text-indent: 100%; - width: 4rem; - height: 2rem; - transition: left 0.15s ease-out; } - .switch input { - left: 10px; - opacity: 0; - padding: 0; - position: absolute; - top: 9px; } - .switch input + label { - margin-left: 0; - margin-right: 0; } - .switch label:after { - background: #FFFFFF; - content: ""; - display: block; - height: 1.5rem; - left: .25rem; - position: absolute; - top: .25rem; - width: 1.5rem; - -webkit-transition: left 0.15s ease-out; - -moz-transition: left 0.15s ease-out; - -o-transition: translate3d(0, 0, 0); - transition: left 0.15s ease-out; - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - -o-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); } - .switch input:checked + label { - background: #008CBA; } - .switch input:checked + label:after { - left: 2.25rem; } - .switch label { - height: 2rem; - width: 4rem; } - .switch label:after { - height: 1.5rem; - width: 1.5rem; } - .switch input:checked + label:after { - left: 2.25rem; } - .switch label { - color: transparent; - background: #DDDDDD; } - .switch label:after { - background: #FFFFFF; } - .switch input:checked + label { - background: #008CBA; } - .switch.large label { - height: 2.5rem; - width: 5rem; } - .switch.large label:after { - height: 2rem; - width: 2rem; } - .switch.large input:checked + label:after { - left: 2.75rem; } - .switch.small label { - height: 1.75rem; - width: 3.5rem; } - .switch.small label:after { - height: 1.25rem; - width: 1.25rem; } - .switch.small input:checked + label:after { - left: 2rem; } - .switch.tiny label { - height: 1.5rem; - width: 3rem; } - .switch.tiny label:after { - height: 1rem; - width: 1rem; } - .switch.tiny input:checked + label:after { - left: 1.75rem; } - .switch.radius label { - border-radius: 4px; } - .switch.radius label:after { - border-radius: 3px; } - .switch.round { - border-radius: 1000px; } - .switch.round label { - border-radius: 2rem; } - .switch.round label:after { - border-radius: 2rem; } - -table { - background: #FFFFFF; - border: solid 1px #DDDDDD; - margin-bottom: 1.25rem; - table-layout: auto; } - table caption { - background: transparent; - color: #222222; - font-size: 1rem; - font-weight: bold; } - table thead { - background: #F5F5F5; } - table thead tr th, - table thead tr td { - color: #222222; - font-size: 0.875rem; - font-weight: bold; - padding: 0.5rem 0.625rem 0.625rem; } - table tfoot { - background: #F5F5F5; } - table tfoot tr th, - table tfoot tr td { - color: #222222; - font-size: 0.875rem; - font-weight: bold; - padding: 0.5rem 0.625rem 0.625rem; } - table tr th, - table tr td { - color: #222222; - font-size: 0.875rem; - padding: 0.5625rem 0.625rem; - text-align: left; } - table tr.even, table tr.alt, table tr:nth-of-type(even) { - background: #F9F9F9; } - table thead tr th, - table tfoot tr th, - table tfoot tr td, - table tbody tr th, - table tbody tr td, - table tr td { - display: table-cell; - line-height: 1.125rem; } - -.tabs { - margin-bottom: 0 !important; - margin-left: 0; } - .tabs:before, .tabs:after { - content: " "; - display: table; } - .tabs:after { - clear: both; } - .tabs dd, - .tabs .tab-title { - float: left; - list-style: none; - margin-bottom: 0 !important; - position: relative; } - .tabs dd > a, - .tabs .tab-title > a { - display: block; - background-color: #EFEFEF; - color: #222222; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-size: 1rem; - padding: 1rem 2rem; } - .tabs dd > a:hover, - .tabs .tab-title > a:hover { - background-color: #e1e1e1; } - .tabs dd.active > a, - .tabs .tab-title.active > a { - background-color: #FFFFFF; - color: #222222; } - .tabs.radius dd:first-child a, - .tabs.radius .tab:first-child a { - -webkit-border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border-top-left-radius: 3px; } - .tabs.radius dd:last-child a, - .tabs.radius .tab:last-child a { - -webkit-border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - border-top-right-radius: 3px; } - .tabs.vertical dd, - .tabs.vertical .tab-title { - position: inherit; - float: none; - display: block; - top: auto; } - -.tabs-content { - margin-bottom: 1.5rem; - width: 100%; } - .tabs-content:before, .tabs-content:after { - content: " "; - display: table; } - .tabs-content:after { - clear: both; } - .tabs-content > .content { - display: none; - float: left; - padding: 0.9375rem 0; - width: 100%; } - .tabs-content > .content.active { - display: block; - float: none; } - .tabs-content > .content.contained { - padding: 0.9375rem; } - .tabs-content.vertical { - display: block; } - .tabs-content.vertical > .content { - padding: 0 0.9375rem; } - -@media only screen and (min-width: 40.0625em) { - .tabs.vertical { - float: left; - margin: 0; - margin-bottom: 1.25rem !important; - max-width: 20%; - width: 20%; } - - .tabs-content.vertical { - float: left; - margin-left: -1px; - max-width: 80%; - padding-left: 1rem; - width: 80%; } } -.no-js .tabs-content > .content { - display: block; - float: none; } - -/* Image Thumbnails */ -.th { - border: solid 4px #FFFFFF; - box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2); - display: inline-block; - line-height: 0; - max-width: 100%; - transition: all 200ms ease-out; } - .th:hover, .th:focus { - box-shadow: 0 0 6px 1px rgba(0, 140, 186, 0.5); } - .th.radius { - border-radius: 3px; } - -/* Tooltips */ -.has-tip { - border-bottom: dotted 1px #CCCCCC; - color: #333333; - cursor: help; - font-weight: bold; } - .has-tip:hover, .has-tip:focus { - border-bottom: dotted 1px #003f54; - color: #008CBA; } - .has-tip.tip-left, .has-tip.tip-right { - float: none !important; } - -.tooltip { - background: #333333; - color: #FFFFFF; - display: none; - font-size: 0.875rem; - font-weight: normal; - line-height: 1.3; - max-width: 300px; - padding: 0.75rem; - position: absolute; - width: 100%; - z-index: 1006; - left: 50%; } - .tooltip > .nub { - border: solid 5px; - border-color: transparent transparent #333333 transparent; - display: block; - height: 0; - pointer-events: none; - position: absolute; - top: -10px; - width: 0; - left: 5px; } - .tooltip > .nub.rtl { - left: auto; - right: 5px; } - .tooltip.radius { - border-radius: 3px; } - .tooltip.round { - border-radius: 1000px; } - .tooltip.round > .nub { - left: 2rem; } - .tooltip.opened { - border-bottom: dotted 1px #003f54 !important; - color: #008CBA !important; } - -.tap-to-close { - color: #777777; - display: block; - font-size: 0.625rem; - font-weight: normal; } - -@media only screen { - .tooltip > .nub { - border-color: transparent transparent #333333 transparent; - top: -10px; } - .tooltip.tip-top > .nub { - border-color: #333333 transparent transparent transparent; - bottom: -10px; - top: auto; } - .tooltip.tip-left, .tooltip.tip-right { - float: none !important; } - .tooltip.tip-left > .nub { - border-color: transparent transparent transparent #333333; - left: auto; - margin-top: -5px; - right: -10px; - top: 50%; } - .tooltip.tip-right > .nub { - border-color: transparent #333333 transparent transparent; - left: -10px; - margin-top: -5px; - right: auto; - top: 50%; } } -meta.foundation-mq-topbar { - font-family: "/only screen and (min-width:40.0625em)/"; - width: 40.0625em; } - -/* Wrapped around .top-bar to contain to grid width */ -.contain-to-grid { - width: 100%; - background: #333333; } - .contain-to-grid .top-bar { - margin-bottom: 0; } - -.fixed { - position: fixed; - top: 0; - width: 100%; - z-index: 99; - left: 0; } - .fixed.expanded:not(.top-bar) { - height: auto; - max-height: 100%; - overflow-y: auto; - width: 100%; } - .fixed.expanded:not(.top-bar) .title-area { - position: fixed; - width: 100%; - z-index: 99; } - .fixed.expanded:not(.top-bar) .top-bar-section { - margin-top: 2.8125rem; - z-index: 98; } - -.top-bar { - background: #333333; - height: 2.8125rem; - line-height: 2.8125rem; - margin-bottom: 0; - overflow: hidden; - position: relative; } - .top-bar ul { - list-style: none; - margin-bottom: 0; } - .top-bar .row { - max-width: none; } - .top-bar form, - .top-bar input, - .top-bar select { - margin-bottom: 0; } - .top-bar input, - .top-bar select { - font-size: 0.75rem; - height: 1.75rem; - padding-bottom: .35rem; - padding-top: .35rem; } - .top-bar .button, .top-bar button { - font-size: 0.75rem; - margin-bottom: 0; - padding-bottom: 0.4125rem; - padding-top: 0.4125rem; } - @media only screen and (max-width: 40em) { - .top-bar .button, .top-bar button { - position: relative; - top: -1px; } } - .top-bar .title-area { - margin: 0; - position: relative; } - .top-bar .name { - font-size: 16px; - height: 2.8125rem; - margin: 0; } - .top-bar .name h1, .top-bar .name h2, .top-bar .name h3, .top-bar .name h4, .top-bar .name p, .top-bar .name span { - font-size: 1.0625rem; - line-height: 2.8125rem; - margin: 0; } - .top-bar .name h1 a, .top-bar .name h2 a, .top-bar .name h3 a, .top-bar .name h4 a, .top-bar .name p a, .top-bar .name span a { - color: #FFFFFF; - display: block; - font-weight: normal; - padding: 0 0.9375rem; - width: 75%; } - .top-bar .toggle-topbar { - position: absolute; - right: 0; - top: 0; } - .top-bar .toggle-topbar a { - color: #FFFFFF; - display: block; - font-size: 0.8125rem; - font-weight: bold; - height: 2.8125rem; - line-height: 2.8125rem; - padding: 0 0.9375rem; - position: relative; - text-transform: uppercase; } - .top-bar .toggle-topbar.menu-icon { - margin-top: -16px; - top: 50%; } - .top-bar .toggle-topbar.menu-icon a { - color: #FFFFFF; - height: 34px; - line-height: 33px; - padding: 0 2.5rem 0 0.9375rem; - position: relative; } - .top-bar .toggle-topbar.menu-icon a span::after { - content: ""; - display: block; - height: 0; - position: absolute; - margin-top: -8px; - top: 50%; - right: 0.9375rem; - box-shadow: 0 0 0 1px #FFFFFF, 0 7px 0 1px #FFFFFF, 0 14px 0 1px #FFFFFF; - width: 16px; } - .top-bar .toggle-topbar.menu-icon a span:hover:after { - box-shadow: 0 0 0 1px "", 0 7px 0 1px "", 0 14px 0 1px ""; } - .top-bar.expanded { - background: transparent; - height: auto; } - .top-bar.expanded .title-area { - background: #333333; } - .top-bar.expanded .toggle-topbar a { - color: #888888; } - .top-bar.expanded .toggle-topbar a span::after { - box-shadow: 0 0 0 1px #888888, 0 7px 0 1px #888888, 0 14px 0 1px #888888; } - @media screen and (-webkit-min-device-pixel-ratio: 0) { - .top-bar.expanded .top-bar-section .has-dropdown.moved > .dropdown, - .top-bar.expanded .top-bar-section .dropdown { - clip: initial; } - .top-bar.expanded .top-bar-section .has-dropdown:not(.moved) > ul { - padding: 0; } } - -.top-bar-section { - left: 0; - position: relative; - width: auto; - transition: left 300ms ease-out; } - .top-bar-section ul { - display: block; - font-size: 16px; - height: auto; - margin: 0; - padding: 0; - width: 100%; } - .top-bar-section .divider, - .top-bar-section [role="separator"] { - border-top: solid 1px #1a1a1a; - clear: both; - height: 1px; - width: 100%; } - .top-bar-section ul li { - background: #333333; } - .top-bar-section ul li > a { - color: #FFFFFF; - display: block; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-size: 0.8125rem; - font-weight: normal; - padding-left: 0.9375rem; - padding: 12px 0 12px 0.9375rem; - text-transform: none; - width: 100%; } - .top-bar-section ul li > a.button { - font-size: 0.8125rem; - padding-left: 0.9375rem; - padding-right: 0.9375rem; - background-color: #008CBA; - border-color: #007095; - color: #FFFFFF; } - .top-bar-section ul li > a.button:hover, .top-bar-section ul li > a.button:focus { - background-color: #007095; } - .top-bar-section ul li > a.button:hover, .top-bar-section ul li > a.button:focus { - color: #FFFFFF; } - .top-bar-section ul li > a.button.secondary { - background-color: #e7e7e7; - border-color: #b9b9b9; - color: #333333; } - .top-bar-section ul li > a.button.secondary:hover, .top-bar-section ul li > a.button.secondary:focus { - background-color: #b9b9b9; } - .top-bar-section ul li > a.button.secondary:hover, .top-bar-section ul li > a.button.secondary:focus { - color: #333333; } - .top-bar-section ul li > a.button.success { - background-color: #43AC6A; - border-color: #368a55; - color: #FFFFFF; } - .top-bar-section ul li > a.button.success:hover, .top-bar-section ul li > a.button.success:focus { - background-color: #368a55; } - .top-bar-section ul li > a.button.success:hover, .top-bar-section ul li > a.button.success:focus { - color: #FFFFFF; } - .top-bar-section ul li > a.button.alert { - background-color: #f04124; - border-color: #cf2a0e; - color: #FFFFFF; } - .top-bar-section ul li > a.button.alert:hover, .top-bar-section ul li > a.button.alert:focus { - background-color: #cf2a0e; } - .top-bar-section ul li > a.button.alert:hover, .top-bar-section ul li > a.button.alert:focus { - color: #FFFFFF; } - .top-bar-section ul li > a.button.warning { - background-color: #f08a24; - border-color: #cf6e0e; - color: #FFFFFF; } - .top-bar-section ul li > a.button.warning:hover, .top-bar-section ul li > a.button.warning:focus { - background-color: #cf6e0e; } - .top-bar-section ul li > a.button.warning:hover, .top-bar-section ul li > a.button.warning:focus { - color: #FFFFFF; } - .top-bar-section ul li > a.button.info { - background-color: #a0d3e8; - border-color: #61b6d9; - color: #333333; } - .top-bar-section ul li > a.button.info:hover, .top-bar-section ul li > a.button.info:focus { - background-color: #61b6d9; } - .top-bar-section ul li > a.button.info:hover, .top-bar-section ul li > a.button.info:focus { - color: #FFFFFF; } - .top-bar-section ul li > button { - font-size: 0.8125rem; - padding-left: 0.9375rem; - padding-right: 0.9375rem; - background-color: #008CBA; - border-color: #007095; - color: #FFFFFF; } - .top-bar-section ul li > button:hover, .top-bar-section ul li > button:focus { - background-color: #007095; } - .top-bar-section ul li > button:hover, .top-bar-section ul li > button:focus { - color: #FFFFFF; } - .top-bar-section ul li > button.secondary { - background-color: #e7e7e7; - border-color: #b9b9b9; - color: #333333; } - .top-bar-section ul li > button.secondary:hover, .top-bar-section ul li > button.secondary:focus { - background-color: #b9b9b9; } - .top-bar-section ul li > button.secondary:hover, .top-bar-section ul li > button.secondary:focus { - color: #333333; } - .top-bar-section ul li > button.success { - background-color: #43AC6A; - border-color: #368a55; - color: #FFFFFF; } - .top-bar-section ul li > button.success:hover, .top-bar-section ul li > button.success:focus { - background-color: #368a55; } - .top-bar-section ul li > button.success:hover, .top-bar-section ul li > button.success:focus { - color: #FFFFFF; } - .top-bar-section ul li > button.alert { - background-color: #f04124; - border-color: #cf2a0e; - color: #FFFFFF; } - .top-bar-section ul li > button.alert:hover, .top-bar-section ul li > button.alert:focus { - background-color: #cf2a0e; } - .top-bar-section ul li > button.alert:hover, .top-bar-section ul li > button.alert:focus { - color: #FFFFFF; } - .top-bar-section ul li > button.warning { - background-color: #f08a24; - border-color: #cf6e0e; - color: #FFFFFF; } - .top-bar-section ul li > button.warning:hover, .top-bar-section ul li > button.warning:focus { - background-color: #cf6e0e; } - .top-bar-section ul li > button.warning:hover, .top-bar-section ul li > button.warning:focus { - color: #FFFFFF; } - .top-bar-section ul li > button.info { - background-color: #a0d3e8; - border-color: #61b6d9; - color: #333333; } - .top-bar-section ul li > button.info:hover, .top-bar-section ul li > button.info:focus { - background-color: #61b6d9; } - .top-bar-section ul li > button.info:hover, .top-bar-section ul li > button.info:focus { - color: #FFFFFF; } - .top-bar-section ul li:hover:not(.has-form) > a { - background-color: #555555; - color: #FFFFFF; - background: #222222; } - .top-bar-section ul li.active > a { - background: #008CBA; - color: #FFFFFF; } - .top-bar-section ul li.active > a:hover { - background: #0078a0; - color: #FFFFFF; } - .top-bar-section .has-form { - padding: 0.9375rem; } - .top-bar-section .has-dropdown { - position: relative; } - .top-bar-section .has-dropdown > a:after { - border: inset 5px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: transparent transparent transparent rgba(255, 255, 255, 0.4); - border-left-style: solid; - margin-right: 0.9375rem; - margin-top: -4.5px; - position: absolute; - top: 50%; - right: 0; } - .top-bar-section .has-dropdown.moved { - position: static; } - .top-bar-section .has-dropdown.moved > .dropdown { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; - display: block; - position: absolute !important; - width: 100%; } - .top-bar-section .has-dropdown.moved > a:after { - display: none; } - .top-bar-section .dropdown { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; - display: block; - padding: 0; - position: absolute; - top: 0; - z-index: 99; - left: 100%; } - .top-bar-section .dropdown li { - height: auto; - width: 100%; } - .top-bar-section .dropdown li a { - font-weight: normal; - padding: 8px 0.9375rem; } - .top-bar-section .dropdown li a.parent-link { - font-weight: normal; } - .top-bar-section .dropdown li.title h5, .top-bar-section .dropdown li.parent-link { - margin-bottom: 0; - margin-top: 0; - font-size: 1.125rem; } - .top-bar-section .dropdown li.title h5 a, .top-bar-section .dropdown li.parent-link a { - color: #FFFFFF; - display: block; } - .top-bar-section .dropdown li.title h5 a:hover, .top-bar-section .dropdown li.parent-link a:hover { - background: none; } - .top-bar-section .dropdown li.has-form { - padding: 8px 0.9375rem; } - .top-bar-section .dropdown li .button, - .top-bar-section .dropdown li button { - top: auto; } - .top-bar-section .dropdown label { - color: #777777; - font-size: 0.625rem; - font-weight: bold; - margin-bottom: 0; - padding: 8px 0.9375rem 2px; - text-transform: uppercase; } - -.js-generated { - display: block; } - -@media only screen and (min-width: 40.0625em) { - .top-bar { - background: #333333; - overflow: visible; } - .top-bar:before, .top-bar:after { - content: " "; - display: table; } - .top-bar:after { - clear: both; } - .top-bar .toggle-topbar { - display: none; } - .top-bar .title-area { - float: left; } - .top-bar .name h1 a, - .top-bar .name h2 a, - .top-bar .name h3 a, - .top-bar .name h4 a, - .top-bar .name h5 a, - .top-bar .name h6 a { - width: auto; } - .top-bar input, - .top-bar select, - .top-bar .button, - .top-bar button { - font-size: 0.875rem; - height: 1.75rem; - position: relative; - top: 0.53125rem; } - .top-bar .has-form > .button, - .top-bar .has-form > button { - font-size: 0.875rem; - height: 1.75rem; - position: relative; - top: 0.53125rem; } - .top-bar.expanded { - background: #333333; } - - .contain-to-grid .top-bar { - margin: 0 auto; - margin-bottom: 0; - max-width: 62.5rem; } - - .top-bar-section { - transition: none 0 0; - left: 0 !important; } - .top-bar-section ul { - display: inline; - height: auto !important; - width: auto; } - .top-bar-section ul li { - float: left; } - .top-bar-section ul li .js-generated { - display: none; } - .top-bar-section li.hover > a:not(.button) { - background-color: #555555; - background: #222222; - color: #FFFFFF; } - .top-bar-section li:not(.has-form) a:not(.button) { - background: #333333; - line-height: 2.8125rem; - padding: 0 0.9375rem; } - .top-bar-section li:not(.has-form) a:not(.button):hover { - background-color: #555555; - background: #222222; } - .top-bar-section li.active:not(.has-form) a:not(.button) { - background: #008CBA; - color: #FFFFFF; - line-height: 2.8125rem; - padding: 0 0.9375rem; } - .top-bar-section li.active:not(.has-form) a:not(.button):hover { - background: #0078a0; - color: #FFFFFF; } - .top-bar-section .has-dropdown > a { - padding-right: 2.1875rem !important; } - .top-bar-section .has-dropdown > a:after { - border: inset 5px; - content: ""; - display: block; - height: 0; - width: 0; - border-color: rgba(255, 255, 255, 0.4) transparent transparent transparent; - border-top-style: solid; - margin-top: -2.5px; - top: 1.40625rem; } - .top-bar-section .has-dropdown.moved { - position: relative; } - .top-bar-section .has-dropdown.moved > .dropdown { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; - display: block; } - .top-bar-section .has-dropdown.hover > .dropdown, .top-bar-section .has-dropdown.not-click:hover > .dropdown { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; - display: block; - position: absolute !important; } - .top-bar-section .has-dropdown > a:focus + .dropdown { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; - display: block; - position: absolute !important; } - .top-bar-section .has-dropdown .dropdown li.has-dropdown > a:after { - border: none; - content: "\00bb"; - top: 0.1875rem; - right: 5px; } - .top-bar-section .dropdown { - left: 0; - background: transparent; - min-width: 100%; - top: auto; } - .top-bar-section .dropdown li a { - background: #333333; - color: #FFFFFF; - line-height: 2.8125rem; - padding: 12px 0.9375rem; - white-space: nowrap; } - .top-bar-section .dropdown li:not(.has-form):not(.active) > a:not(.button) { - background: #333333; - color: #FFFFFF; } - .top-bar-section .dropdown li:not(.has-form):not(.active):hover > a:not(.button) { - background-color: #555555; - color: #FFFFFF; - background: #222222; } - .top-bar-section .dropdown li label { - background: #333333; - white-space: nowrap; } - .top-bar-section .dropdown li .dropdown { - left: 100%; - top: 0; } - .top-bar-section > ul > .divider, - .top-bar-section > ul > [role="separator"] { - border-right: solid 1px #4e4e4e; - border-bottom: none; - border-top: none; - clear: none; - height: 2.8125rem; - width: 0; } - .top-bar-section .has-form { - background: #333333; - height: 2.8125rem; - padding: 0 0.9375rem; } - .top-bar-section .right li .dropdown { - left: auto; - right: 0; } - .top-bar-section .right li .dropdown li .dropdown { - right: 100%; } - .top-bar-section .left li .dropdown { - right: auto; - left: 0; } - .top-bar-section .left li .dropdown li .dropdown { - left: 100%; } - - .no-js .top-bar-section ul li:hover > a { - background-color: #555555; - background: #222222; - color: #FFFFFF; } - .no-js .top-bar-section ul li:active > a { - background: #008CBA; - color: #FFFFFF; } - .no-js .top-bar-section .has-dropdown:hover > .dropdown { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; - display: block; - position: absolute !important; } - .no-js .top-bar-section .has-dropdown > a:focus + .dropdown { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; - display: block; - position: absolute !important; } } -.text-left { - text-align: left !important; } - -.text-right { - text-align: right !important; } - -.text-center { - text-align: center !important; } - -.text-justify { - text-align: justify !important; } - -@media only screen and (max-width: 40em) { - .small-only-text-left { - text-align: left !important; } - - .small-only-text-right { - text-align: right !important; } - - .small-only-text-center { - text-align: center !important; } - - .small-only-text-justify { - text-align: justify !important; } } -@media only screen { - .small-text-left { - text-align: left !important; } - - .small-text-right { - text-align: right !important; } - - .small-text-center { - text-align: center !important; } - - .small-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 40.0625em) and (max-width: 64em) { - .medium-only-text-left { - text-align: left !important; } - - .medium-only-text-right { - text-align: right !important; } - - .medium-only-text-center { - text-align: center !important; } - - .medium-only-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 40.0625em) { - .medium-text-left { - text-align: left !important; } - - .medium-text-right { - text-align: right !important; } - - .medium-text-center { - text-align: center !important; } - - .medium-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 64.0625em) and (max-width: 90em) { - .large-only-text-left { - text-align: left !important; } - - .large-only-text-right { - text-align: right !important; } - - .large-only-text-center { - text-align: center !important; } - - .large-only-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 64.0625em) { - .large-text-left { - text-align: left !important; } - - .large-text-right { - text-align: right !important; } - - .large-text-center { - text-align: center !important; } - - .large-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 90.0625em) and (max-width: 120em) { - .xlarge-only-text-left { - text-align: left !important; } - - .xlarge-only-text-right { - text-align: right !important; } - - .xlarge-only-text-center { - text-align: center !important; } - - .xlarge-only-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 90.0625em) { - .xlarge-text-left { - text-align: left !important; } - - .xlarge-text-right { - text-align: right !important; } - - .xlarge-text-center { - text-align: center !important; } - - .xlarge-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 120.0625em) and (max-width: 6249999.9375em) { - .xxlarge-only-text-left { - text-align: left !important; } - - .xxlarge-only-text-right { - text-align: right !important; } - - .xxlarge-only-text-center { - text-align: center !important; } - - .xxlarge-only-text-justify { - text-align: justify !important; } } -@media only screen and (min-width: 120.0625em) { - .xxlarge-text-left { - text-align: left !important; } - - .xxlarge-text-right { - text-align: right !important; } - - .xxlarge-text-center { - text-align: center !important; } - - .xxlarge-text-justify { - text-align: justify !important; } } -/* Typography resets */ -div, -dl, -dt, -dd, -ul, -ol, -li, -h1, -h2, -h3, -h4, -h5, -h6, -pre, -form, -p, -blockquote, -th, -td { - margin: 0; - padding: 0; } - -/* Default Link Styles */ -a { - color: #008CBA; - line-height: inherit; - text-decoration: none; } - a:hover, a:focus { - color: #0078a0; } - a img { - border: none; } - -/* Default paragraph styles */ -p { - font-family: inherit; - font-size: 1rem; - font-weight: normal; - line-height: 1.6; - margin-bottom: 1.25rem; - text-rendering: optimizeLegibility; } - p.lead { - font-size: 1.21875rem; - line-height: 1.6; } - p aside { - font-size: 0.875rem; - font-style: italic; - line-height: 1.35; } - -/* Default header styles */ -h1, h2, h3, h4, h5, h6 { - color: #222222; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-style: normal; - font-weight: normal; - line-height: 1.4; - margin-bottom: 0.5rem; - margin-top: 0.2rem; - text-rendering: optimizeLegibility; } - h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { - color: #6f6f6f; - font-size: 60%; - line-height: 0; } - -h1 { - font-size: 2.125rem; } - -h2 { - font-size: 1.6875rem; } - -h3 { - font-size: 1.375rem; } - -h4 { - font-size: 1.125rem; } - -h5 { - font-size: 1.125rem; } - -h6 { - font-size: 1rem; } - -.subheader { - line-height: 1.4; - color: #6f6f6f; - font-weight: normal; - margin-top: 0.2rem; - margin-bottom: 0.5rem; } - -hr { - border: solid #DDDDDD; - border-width: 1px 0 0; - clear: both; - height: 0; - margin: 1.25rem 0 1.1875rem; } - -/* Helpful Typography Defaults */ -em, -i { - font-style: italic; - line-height: inherit; } - -strong, -b { - font-weight: bold; - line-height: inherit; } - -small { - font-size: 60%; - line-height: inherit; } - -code { - background-color: #f8f8f8; - border-color: #dfdfdf; - border-style: solid; - border-width: 1px; - color: #333333; - font-family: Consolas, "Liberation Mono", Courier, monospace; - font-weight: normal; - padding: 0.125rem 0.3125rem 0.0625rem; } - -/* Lists */ -ul, -ol, -dl { - font-family: inherit; - font-size: 1rem; - line-height: 1.6; - list-style-position: outside; - margin-bottom: 1.25rem; } - -ul { - margin-left: 1.1rem; } - -/* Unordered Lists */ -ul li ul, -ul li ol { - margin-left: 1.25rem; - margin-bottom: 0; } -ul.square li ul, ul.circle li ul, ul.disc li ul { - list-style: inherit; } -ul.square { - list-style-type: square; - margin-left: 1.1rem; } -ul.circle { - list-style-type: circle; - margin-left: 1.1rem; } -ul.disc { - list-style-type: disc; - margin-left: 1.1rem; } - -/* Ordered Lists */ -ol { - margin-left: 1.4rem; } - ol li ul, - ol li ol { - margin-left: 1.25rem; - margin-bottom: 0; } - -.no-bullet { - list-style-type: none; - margin-left: 0; } - .no-bullet li ul, - .no-bullet li ol { - margin-left: 1.25rem; - margin-bottom: 0; - list-style: none; } - -/* Definition Lists */ -dl dt { - margin-bottom: 0.3rem; - font-weight: bold; } -dl dd { - margin-bottom: 0.75rem; } - -/* Abbreviations */ -abbr, -acronym { - text-transform: uppercase; - font-size: 90%; - color: #222; - cursor: help; } - -abbr { - text-transform: none; } - abbr[title] { - border-bottom: 1px dotted #DDDDDD; } - -/* Blockquotes */ -blockquote { - margin: 0 0 1.25rem; - padding: 0.5625rem 1.25rem 0 1.1875rem; - border-left: 1px solid #DDDDDD; } - blockquote cite { - display: block; - font-size: 0.8125rem; - color: #555555; } - blockquote cite:before { - content: "\2014 \0020"; } - blockquote cite a, - blockquote cite a:visited { - color: #555555; } - -blockquote, -blockquote p { - line-height: 1.6; - color: #6f6f6f; } - -/* Microformats */ -.vcard { - display: inline-block; - margin: 0 0 1.25rem 0; - border: 1px solid #DDDDDD; - padding: 0.625rem 0.75rem; } - .vcard li { - margin: 0; - display: block; } - .vcard .fn { - font-weight: bold; - font-size: 0.9375rem; } - -.vevent .summary { - font-weight: bold; } -.vevent abbr { - cursor: default; - text-decoration: none; - font-weight: bold; - border: none; - padding: 0 0.0625rem; } - -@media only screen and (min-width: 40.0625em) { - h1, h2, h3, h4, h5, h6 { - line-height: 1.4; } - - h1 { - font-size: 2.75rem; } - - h2 { - font-size: 2.3125rem; } - - h3 { - font-size: 1.6875rem; } - - h4 { - font-size: 1.4375rem; } - - h5 { - font-size: 1.125rem; } - - h6 { - font-size: 1rem; } } -/* - * Print styles. - * - * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/ - * Credit to Paul Irish and HTML5 Boilerplate (html5boilerplate.com) -*/ -@media print { - * { - background: transparent !important; - color: #000000 !important; - /* Black prints faster: h5bp.com/s */ - box-shadow: none !important; - text-shadow: none !important; } - - a, - a:visited { - text-decoration: underline; } - - a[href]:after { - content: " (" attr(href) ")"; } - - abbr[title]:after { - content: " (" attr(title) ")"; } - - .ir a:after, - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; } - - pre, - blockquote { - border: 1px solid #999999; - page-break-inside: avoid; } - - thead { - display: table-header-group; - /* h5bp.com/t */ } - - tr, - img { - page-break-inside: avoid; } - - img { - max-width: 100% !important; } - - @page { - margin: 0.34in; } - p, - h2, - h3 { - orphans: 3; - widows: 3; } - - h2, - h3 { - page-break-after: avoid; } } -.off-canvas-wrap { - -webkit-backface-visibility: hidden; - position: relative; - width: 100%; - overflow: hidden; } - .off-canvas-wrap.move-right, .off-canvas-wrap.move-left, .off-canvas-wrap.move-bottom, .off-canvas-wrap.move-top { - min-height: 100%; - -webkit-overflow-scrolling: touch; } - -.inner-wrap { - position: relative; - width: 100%; - -webkit-transition: -webkit-transform 500ms ease; - -moz-transition: -moz-transform 500ms ease; - -ms-transition: -ms-transform 500ms ease; - -o-transition: -o-transform 500ms ease; - transition: transform 500ms ease; } - .inner-wrap:before, .inner-wrap:after { - content: " "; - display: table; } - .inner-wrap:after { - clear: both; } - -.tab-bar { - -webkit-backface-visibility: hidden; - background: #333333; - color: #FFFFFF; - height: 2.8125rem; - line-height: 2.8125rem; - position: relative; } - .tab-bar h1, .tab-bar h2, .tab-bar h3, .tab-bar h4, .tab-bar h5, .tab-bar h6 { - color: #FFFFFF; - font-weight: bold; - line-height: 2.8125rem; - margin: 0; } - .tab-bar h1, .tab-bar h2, .tab-bar h3, .tab-bar h4 { - font-size: 1.125rem; } - -.left-small { - height: 2.8125rem; - position: absolute; - top: 0; - width: 2.8125rem; - border-right: solid 1px #1a1a1a; - left: 0; } - -.right-small { - height: 2.8125rem; - position: absolute; - top: 0; - width: 2.8125rem; - border-left: solid 1px #1a1a1a; - right: 0; } - -.tab-bar-section { - height: 2.8125rem; - padding: 0 0.625rem; - position: absolute; - text-align: center; - top: 0; } - .tab-bar-section.left { - text-align: left; } - .tab-bar-section.right { - text-align: right; } - .tab-bar-section.left { - left: 0; - right: 2.8125rem; } - .tab-bar-section.right { - left: 2.8125rem; - right: 0; } - .tab-bar-section.middle { - left: 2.8125rem; - right: 2.8125rem; } - -.tab-bar .menu-icon { - color: #FFFFFF; - display: block; - height: 2.8125rem; - padding: 0; - position: relative; - text-indent: 2.1875rem; - transform: translate3d(0, 0, 0); - width: 2.8125rem; } - .tab-bar .menu-icon span::after { - content: ""; - display: block; - height: 0; - position: absolute; - top: 50%; - margin-top: -0.5rem; - left: 0.90625rem; - box-shadow: 0 0 0 1px #FFFFFF, 0 7px 0 1px #FFFFFF, 0 14px 0 1px #FFFFFF; - width: 1rem; } - .tab-bar .menu-icon span:hover:after { - box-shadow: 0 0 0 1px #b3b3b3, 0 7px 0 1px #b3b3b3, 0 14px 0 1px #b3b3b3; } - -.left-off-canvas-menu { - -webkit-backface-visibility: hidden; - background: #333333; - bottom: 0; - box-sizing: content-box; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - transition: transform 500ms ease 0s; - width: 15.625rem; - z-index: 1001; - -webkit-transform: translate3d(-100%, 0, 0); - -moz-transform: translate3d(-100%, 0, 0); - -ms-transform: translate(-100%, 0); - -o-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - left: 0; - top: 0; } - .left-off-canvas-menu * { - -webkit-backface-visibility: hidden; } - -.right-off-canvas-menu { - -webkit-backface-visibility: hidden; - background: #333333; - bottom: 0; - box-sizing: content-box; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - transition: transform 500ms ease 0s; - width: 15.625rem; - z-index: 1001; - -webkit-transform: translate3d(100%, 0, 0); - -moz-transform: translate3d(100%, 0, 0); - -ms-transform: translate(100%, 0); - -o-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - right: 0; - top: 0; } - .right-off-canvas-menu * { - -webkit-backface-visibility: hidden; } - -.top-off-canvas-menu { - -webkit-backface-visibility: hidden; - background: #333333; - bottom: 0; - box-sizing: content-box; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - transition: transform 500ms ease 0s; - width: 15.625rem; - z-index: 1001; - -webkit-transform: translate3d(0, -100%, 0); - -moz-transform: translate3d(0, -100%, 0); - -ms-transform: translate(0, -100%); - -o-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - top: 0; - width: 100%; - height: 18.75rem; } - .top-off-canvas-menu * { - -webkit-backface-visibility: hidden; } - -.bottom-off-canvas-menu { - -webkit-backface-visibility: hidden; - background: #333333; - bottom: 0; - box-sizing: content-box; - -webkit-overflow-scrolling: touch; - -ms-overflow-style: -ms-autohiding-scrollbar; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - transition: transform 500ms ease 0s; - width: 15.625rem; - z-index: 1001; - -webkit-transform: translate3d(0, 100%, 0); - -moz-transform: translate3d(0, 100%, 0); - -ms-transform: translate(0, 100%); - -o-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - bottom: 0; - width: 100%; - height: 18.75rem; } - .bottom-off-canvas-menu * { - -webkit-backface-visibility: hidden; } - -ul.off-canvas-list { - list-style-type: none; - margin: 0; - padding: 0; } - ul.off-canvas-list li label { - background: #444444; - border-bottom: none; - border-top: 1px solid #5e5e5e; - color: #999999; - display: block; - font-size: 0.75rem; - font-weight: bold; - margin: 0; - padding: 0.3rem 0.9375rem; - text-transform: uppercase; } - ul.off-canvas-list li a { - border-bottom: 1px solid #262626; - color: rgba(255, 255, 255, 0.7); - display: block; - padding: 0.66667rem; - transition: background 300ms ease; } - ul.off-canvas-list li a:hover { - background: #242424; } - ul.off-canvas-list li a:active { - background: #242424; } - -.move-right > .inner-wrap { - -webkit-transform: translate3d(15.625rem, 0, 0); - -moz-transform: translate3d(15.625rem, 0, 0); - -ms-transform: translate(15.625rem, 0); - -o-transform: translate3d(15.625rem, 0, 0); - transform: translate3d(15.625rem, 0, 0); } -.move-right .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .move-right .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.move-left > .inner-wrap { - -webkit-transform: translate3d(-15.625rem, 0, 0); - -moz-transform: translate3d(-15.625rem, 0, 0); - -ms-transform: translate(-15.625rem, 0); - -o-transform: translate3d(-15.625rem, 0, 0); - transform: translate3d(-15.625rem, 0, 0); } -.move-left .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .move-left .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.move-top > .inner-wrap { - -webkit-transform: translate3d(0, -18.75rem, 0); - -moz-transform: translate3d(0, -18.75rem, 0); - -ms-transform: translate(0, -18.75rem); - -o-transform: translate3d(0, -18.75rem, 0); - transform: translate3d(0, -18.75rem, 0); } -.move-top .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .move-top .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.move-bottom > .inner-wrap { - -webkit-transform: translate3d(0, 18.75rem, 0); - -moz-transform: translate3d(0, 18.75rem, 0); - -ms-transform: translate(0, 18.75rem); - -o-transform: translate3d(0, 18.75rem, 0); - transform: translate3d(0, 18.75rem, 0); } -.move-bottom .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .move-bottom .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.offcanvas-overlap .left-off-canvas-menu, .offcanvas-overlap .right-off-canvas-menu, -.offcanvas-overlap .top-off-canvas-menu, .offcanvas-overlap .bottom-off-canvas-menu { - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; - transform: none; - z-index: 1003; } -.offcanvas-overlap .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .offcanvas-overlap .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.offcanvas-overlap-left .right-off-canvas-menu { - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; - transform: none; - z-index: 1003; } -.offcanvas-overlap-left .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .offcanvas-overlap-left .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.offcanvas-overlap-right .left-off-canvas-menu { - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; - transform: none; - z-index: 1003; } -.offcanvas-overlap-right .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .offcanvas-overlap-right .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.offcanvas-overlap-top .bottom-off-canvas-menu { - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; - transform: none; - z-index: 1003; } -.offcanvas-overlap-top .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .offcanvas-overlap-top .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.offcanvas-overlap-bottom .top-off-canvas-menu { - -ms-transform: none; - -webkit-transform: none; - -moz-transform: none; - -o-transform: none; - transform: none; - z-index: 1003; } -.offcanvas-overlap-bottom .exit-off-canvas { - -webkit-backface-visibility: hidden; - box-shadow: -4px 0 4px rgba(0, 0, 0, 0.5), 4px 0 4px rgba(0, 0, 0, 0.5); - cursor: pointer; - transition: background 300ms ease; - -webkit-tap-highlight-color: transparent; - background: rgba(255, 255, 255, 0.2); - bottom: 0; - display: block; - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1002; } - @media only screen and (min-width: 40.0625em) { - .offcanvas-overlap-bottom .exit-off-canvas:hover { - background: rgba(255, 255, 255, 0.05); } } - -.no-csstransforms .left-off-canvas-menu { - left: -15.625rem; } -.no-csstransforms .right-off-canvas-menu { - right: -15.625rem; } -.no-csstransforms .top-off-canvas-menu { - top: -18.75rem; } -.no-csstransforms .bottom-off-canvas-menu { - bottom: -18.75rem; } -.no-csstransforms .move-left > .inner-wrap { - right: 15.625rem; } -.no-csstransforms .move-right > .inner-wrap { - left: 15.625rem; } -.no-csstransforms .move-top > .inner-wrap { - right: 18.75rem; } -.no-csstransforms .move-bottom > .inner-wrap { - left: 18.75rem; } - -.left-submenu { - -webkit-backface-visibility: hidden; - -webkit-overflow-scrolling: touch; - background: #333333; - bottom: 0; - box-sizing: content-box; - margin: 0; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - top: 0; - width: 15.625rem; - height: 18.75rem; - z-index: 1002; - -webkit-transform: translate3d(-100%, 0, 0); - -moz-transform: translate3d(-100%, 0, 0); - -ms-transform: translate(-100%, 0); - -o-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - left: 0; - -webkit-transition: -webkit-transform 500ms ease; - -moz-transition: -moz-transform 500ms ease; - -ms-transition: -ms-transform 500ms ease; - -o-transition: -o-transform 500ms ease; - transition: transform 500ms ease; } - .left-submenu * { - -webkit-backface-visibility: hidden; } - .left-submenu .back > a { - background: #444; - border-bottom: none; - border-top: 1px solid #5e5e5e; - color: #999999; - font-weight: bold; - padding: 0.3rem 0.9375rem; - text-transform: uppercase; - margin: 0; } - .left-submenu .back > a:hover { - background: #303030; - border-bottom: none; - border-top: 1px solid #5e5e5e; } - .left-submenu .back > a:before { - content: "\AB"; - margin-right: .5rem; - display: inline; } - .left-submenu.move-right, .left-submenu.offcanvas-overlap-right, .left-submenu.offcanvas-overlap { - -webkit-transform: translate3d(0%, 0, 0); - -moz-transform: translate3d(0%, 0, 0); - -ms-transform: translate(0%, 0); - -o-transform: translate3d(0%, 0, 0); - transform: translate3d(0%, 0, 0); } - -.right-submenu { - -webkit-backface-visibility: hidden; - -webkit-overflow-scrolling: touch; - background: #333333; - bottom: 0; - box-sizing: content-box; - margin: 0; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - top: 0; - width: 15.625rem; - height: 18.75rem; - z-index: 1002; - -webkit-transform: translate3d(100%, 0, 0); - -moz-transform: translate3d(100%, 0, 0); - -ms-transform: translate(100%, 0); - -o-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - right: 0; - -webkit-transition: -webkit-transform 500ms ease; - -moz-transition: -moz-transform 500ms ease; - -ms-transition: -ms-transform 500ms ease; - -o-transition: -o-transform 500ms ease; - transition: transform 500ms ease; } - .right-submenu * { - -webkit-backface-visibility: hidden; } - .right-submenu .back > a { - background: #444; - border-bottom: none; - border-top: 1px solid #5e5e5e; - color: #999999; - font-weight: bold; - padding: 0.3rem 0.9375rem; - text-transform: uppercase; - margin: 0; } - .right-submenu .back > a:hover { - background: #303030; - border-bottom: none; - border-top: 1px solid #5e5e5e; } - .right-submenu .back > a:after { - content: "\BB"; - margin-left: .5rem; - display: inline; } - .right-submenu.move-left, .right-submenu.offcanvas-overlap-left, .right-submenu.offcanvas-overlap { - -webkit-transform: translate3d(0%, 0, 0); - -moz-transform: translate3d(0%, 0, 0); - -ms-transform: translate(0%, 0); - -o-transform: translate3d(0%, 0, 0); - transform: translate3d(0%, 0, 0); } - -.top-submenu { - -webkit-backface-visibility: hidden; - -webkit-overflow-scrolling: touch; - background: #333333; - bottom: 0; - box-sizing: content-box; - margin: 0; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - top: 0; - width: 15.625rem; - height: 18.75rem; - z-index: 1002; - -webkit-transform: translate3d(0, -100%, 0); - -moz-transform: translate3d(0, -100%, 0); - -ms-transform: translate(0, -100%); - -o-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - top: 0; - width: 100%; - -webkit-transition: -webkit-transform 500ms ease; - -moz-transition: -moz-transform 500ms ease; - -ms-transition: -ms-transform 500ms ease; - -o-transition: -o-transform 500ms ease; - transition: transform 500ms ease; } - .top-submenu * { - -webkit-backface-visibility: hidden; } - .top-submenu .back > a { - background: #444; - border-bottom: none; - border-top: 1px solid #5e5e5e; - color: #999999; - font-weight: bold; - padding: 0.3rem 0.9375rem; - text-transform: uppercase; - margin: 0; } - .top-submenu .back > a:hover { - background: #303030; - border-bottom: none; - border-top: 1px solid #5e5e5e; } - .top-submenu.move-bottom, .top-submenu.offcanvas-overlap-bottom, .top-submenu.offcanvas-overlap { - -webkit-transform: translate3d(0, 0%, 0); - -moz-transform: translate3d(0, 0%, 0); - -ms-transform: translate(0, 0%); - -o-transform: translate3d(0, 0%, 0); - transform: translate3d(0, 0%, 0); } - -.bottom-submenu { - -webkit-backface-visibility: hidden; - -webkit-overflow-scrolling: touch; - background: #333333; - bottom: 0; - box-sizing: content-box; - margin: 0; - overflow-x: hidden; - overflow-y: auto; - position: absolute; - top: 0; - width: 15.625rem; - height: 18.75rem; - z-index: 1002; - -webkit-transform: translate3d(0, 100%, 0); - -moz-transform: translate3d(0, 100%, 0); - -ms-transform: translate(0, 100%); - -o-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - bottom: 0; - width: 100%; - -webkit-transition: -webkit-transform 500ms ease; - -moz-transition: -moz-transform 500ms ease; - -ms-transition: -ms-transform 500ms ease; - -o-transition: -o-transform 500ms ease; - transition: transform 500ms ease; } - .bottom-submenu * { - -webkit-backface-visibility: hidden; } - .bottom-submenu .back > a { - background: #444; - border-bottom: none; - border-top: 1px solid #5e5e5e; - color: #999999; - font-weight: bold; - padding: 0.3rem 0.9375rem; - text-transform: uppercase; - margin: 0; } - .bottom-submenu .back > a:hover { - background: #303030; - border-bottom: none; - border-top: 1px solid #5e5e5e; } - .bottom-submenu.move-top, .bottom-submenu.offcanvas-overlap-top, .bottom-submenu.offcanvas-overlap { - -webkit-transform: translate3d(0, 0%, 0); - -moz-transform: translate3d(0, 0%, 0); - -ms-transform: translate(0, 0%); - -o-transform: translate3d(0, 0%, 0); - transform: translate3d(0, 0%, 0); } - -.left-off-canvas-menu ul.off-canvas-list li.has-submenu > a:after { - content: "\BB"; - margin-left: .5rem; - display: inline; } - -.right-off-canvas-menu ul.off-canvas-list li.has-submenu > a:before { - content: "\AB"; - margin-right: .5rem; - display: inline; } - -/* small displays */ -@media only screen { - .show-for-small-only, .show-for-small-up, .show-for-small, .show-for-small-down, .hide-for-medium-only, .hide-for-medium-up, .hide-for-medium, .show-for-medium-down, .hide-for-large-only, .hide-for-large-up, .hide-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down { - display: inherit !important; } - - .hide-for-small-only, .hide-for-small-up, .hide-for-small, .hide-for-small-down, .show-for-medium-only, .show-for-medium-up, .show-for-medium, .hide-for-medium-down, .show-for-large-only, .show-for-large-up, .show-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down { - display: none !important; } - - .visible-for-small-only, .visible-for-small-up, .visible-for-small, .visible-for-small-down, .hidden-for-medium-only, .hidden-for-medium-up, .hidden-for-medium, .visible-for-medium-down, .hidden-for-large-only, .hidden-for-large-up, .hidden-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; } - - .hidden-for-small-only, .hidden-for-small-up, .hidden-for-small, .hidden-for-small-down, .visible-for-medium-only, .visible-for-medium-up, .visible-for-medium, .hidden-for-medium-down, .visible-for-large-only, .visible-for-large-up, .visible-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - - table.show-for-small-only, table.show-for-small-up, table.show-for-small, table.show-for-small-down, table.hide-for-medium-only, table.hide-for-medium-up, table.hide-for-medium, table.show-for-medium-down, table.hide-for-large-only, table.hide-for-large-up, table.hide-for-large, table.show-for-large-down, table.hide-for-xlarge-only, table.hide-for-xlarge-up, table.hide-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down { - display: table !important; } - - thead.show-for-small-only, thead.show-for-small-up, thead.show-for-small, thead.show-for-small-down, thead.hide-for-medium-only, thead.hide-for-medium-up, thead.hide-for-medium, thead.show-for-medium-down, thead.hide-for-large-only, thead.hide-for-large-up, thead.hide-for-large, thead.show-for-large-down, thead.hide-for-xlarge-only, thead.hide-for-xlarge-up, thead.hide-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down { - display: table-header-group !important; } - - tbody.show-for-small-only, tbody.show-for-small-up, tbody.show-for-small, tbody.show-for-small-down, tbody.hide-for-medium-only, tbody.hide-for-medium-up, tbody.hide-for-medium, tbody.show-for-medium-down, tbody.hide-for-large-only, tbody.hide-for-large-up, tbody.hide-for-large, tbody.show-for-large-down, tbody.hide-for-xlarge-only, tbody.hide-for-xlarge-up, tbody.hide-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down { - display: table-row-group !important; } - - tr.show-for-small-only, tr.show-for-small-up, tr.show-for-small, tr.show-for-small-down, tr.hide-for-medium-only, tr.hide-for-medium-up, tr.hide-for-medium, tr.show-for-medium-down, tr.hide-for-large-only, tr.hide-for-large-up, tr.hide-for-large, tr.show-for-large-down, tr.hide-for-xlarge-only, tr.hide-for-xlarge-up, tr.hide-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down { - display: table-row; } - - th.show-for-small-only, td.show-for-small-only, th.show-for-small-up, td.show-for-small-up, th.show-for-small, td.show-for-small, th.show-for-small-down, td.show-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.hide-for-medium-up, td.hide-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.show-for-medium-down, td.show-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.hide-for-large-up, td.hide-for-large-up, th.hide-for-large, td.hide-for-large, th.show-for-large-down, td.show-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.hide-for-xlarge-up, td.hide-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down { - display: table-cell !important; } } -/* medium displays */ -@media only screen and (min-width: 40.0625em) { - .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .show-for-medium-only, .show-for-medium-up, .show-for-medium, .show-for-medium-down, .hide-for-large-only, .hide-for-large-up, .hide-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down { - display: inherit !important; } - - .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .hide-for-medium-only, .hide-for-medium-up, .hide-for-medium, .hide-for-medium-down, .show-for-large-only, .show-for-large-up, .show-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down { - display: none !important; } - - .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .visible-for-medium-only, .visible-for-medium-up, .visible-for-medium, .visible-for-medium-down, .hidden-for-large-only, .hidden-for-large-up, .hidden-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; } - - .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .hidden-for-medium-only, .hidden-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .visible-for-large-only, .visible-for-large-up, .visible-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - - table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.show-for-medium-only, table.show-for-medium-up, table.show-for-medium, table.show-for-medium-down, table.hide-for-large-only, table.hide-for-large-up, table.hide-for-large, table.show-for-large-down, table.hide-for-xlarge-only, table.hide-for-xlarge-up, table.hide-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down { - display: table !important; } - - thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.show-for-medium-only, thead.show-for-medium-up, thead.show-for-medium, thead.show-for-medium-down, thead.hide-for-large-only, thead.hide-for-large-up, thead.hide-for-large, thead.show-for-large-down, thead.hide-for-xlarge-only, thead.hide-for-xlarge-up, thead.hide-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down { - display: table-header-group !important; } - - tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.show-for-medium-only, tbody.show-for-medium-up, tbody.show-for-medium, tbody.show-for-medium-down, tbody.hide-for-large-only, tbody.hide-for-large-up, tbody.hide-for-large, tbody.show-for-large-down, tbody.hide-for-xlarge-only, tbody.hide-for-xlarge-up, tbody.hide-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down { - display: table-row-group !important; } - - tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.show-for-medium-only, tr.show-for-medium-up, tr.show-for-medium, tr.show-for-medium-down, tr.hide-for-large-only, tr.hide-for-large-up, tr.hide-for-large, tr.show-for-large-down, tr.hide-for-xlarge-only, tr.hide-for-xlarge-up, tr.hide-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down { - display: table-row; } - - th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.show-for-medium-only, td.show-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.show-for-medium, td.show-for-medium, th.show-for-medium-down, td.show-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.hide-for-large-up, td.hide-for-large-up, th.hide-for-large, td.hide-for-large, th.show-for-large-down, td.show-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.hide-for-xlarge-up, td.hide-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down { - display: table-cell !important; } } -/* large displays */ -@media only screen and (min-width: 64.0625em) { - .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .hide-for-medium-only, .show-for-medium-up, .hide-for-medium, .hide-for-medium-down, .show-for-large-only, .show-for-large-up, .show-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down { - display: inherit !important; } - - .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .show-for-medium-only, .hide-for-medium-up, .show-for-medium, .show-for-medium-down, .hide-for-large-only, .hide-for-large-up, .hide-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down { - display: none !important; } - - .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .hidden-for-medium-only, .visible-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .visible-for-large-only, .visible-for-large-up, .visible-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; } - - .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .visible-for-medium-only, .hidden-for-medium-up, .visible-for-medium, .visible-for-medium-down, .hidden-for-large-only, .hidden-for-large-up, .hidden-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - - table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.hide-for-medium-only, table.show-for-medium-up, table.hide-for-medium, table.hide-for-medium-down, table.show-for-large-only, table.show-for-large-up, table.show-for-large, table.show-for-large-down, table.hide-for-xlarge-only, table.hide-for-xlarge-up, table.hide-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down { - display: table !important; } - - thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.hide-for-medium-only, thead.show-for-medium-up, thead.hide-for-medium, thead.hide-for-medium-down, thead.show-for-large-only, thead.show-for-large-up, thead.show-for-large, thead.show-for-large-down, thead.hide-for-xlarge-only, thead.hide-for-xlarge-up, thead.hide-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down { - display: table-header-group !important; } - - tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.hide-for-medium-only, tbody.show-for-medium-up, tbody.hide-for-medium, tbody.hide-for-medium-down, tbody.show-for-large-only, tbody.show-for-large-up, tbody.show-for-large, tbody.show-for-large-down, tbody.hide-for-xlarge-only, tbody.hide-for-xlarge-up, tbody.hide-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down { - display: table-row-group !important; } - - tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.hide-for-medium-only, tr.show-for-medium-up, tr.hide-for-medium, tr.hide-for-medium-down, tr.show-for-large-only, tr.show-for-large-up, tr.show-for-large, tr.show-for-large-down, tr.hide-for-xlarge-only, tr.hide-for-xlarge-up, tr.hide-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down { - display: table-row; } - - th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.hide-for-medium-down, td.hide-for-medium-down, th.show-for-large-only, td.show-for-large-only, th.show-for-large-up, td.show-for-large-up, th.show-for-large, td.show-for-large, th.show-for-large-down, td.show-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.hide-for-xlarge-up, td.hide-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down { - display: table-cell !important; } } -/* xlarge displays */ -@media only screen and (min-width: 90.0625em) { - .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .hide-for-medium-only, .show-for-medium-up, .hide-for-medium, .hide-for-medium-down, .hide-for-large-only, .show-for-large-up, .hide-for-large, .hide-for-large-down, .show-for-xlarge-only, .show-for-xlarge-up, .show-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .show-for-xxlarge-down { - display: inherit !important; } - - .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .show-for-medium-only, .hide-for-medium-up, .show-for-medium, .show-for-medium-down, .show-for-large-only, .hide-for-large-up, .show-for-large, .show-for-large-down, .hide-for-xlarge-only, .hide-for-xlarge-up, .hide-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .hide-for-xxlarge-down { - display: none !important; } - - .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .hidden-for-medium-only, .visible-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .hidden-for-large-only, .visible-for-large-up, .hidden-for-large, .hidden-for-large-down, .visible-for-xlarge-only, .visible-for-xlarge-up, .visible-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .visible-for-xxlarge-down { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; } - - .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .visible-for-medium-only, .hidden-for-medium-up, .visible-for-medium, .visible-for-medium-down, .visible-for-large-only, .hidden-for-large-up, .visible-for-large, .visible-for-large-down, .hidden-for-xlarge-only, .hidden-for-xlarge-up, .hidden-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .hidden-for-xxlarge-down { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - - table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.hide-for-medium-only, table.show-for-medium-up, table.hide-for-medium, table.hide-for-medium-down, table.hide-for-large-only, table.show-for-large-up, table.hide-for-large, table.hide-for-large-down, table.show-for-xlarge-only, table.show-for-xlarge-up, table.show-for-xlarge, table.show-for-xlarge-down, table.hide-for-xxlarge-only, table.hide-for-xxlarge-up, table.hide-for-xxlarge, table.show-for-xxlarge-down { - display: table !important; } - - thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.hide-for-medium-only, thead.show-for-medium-up, thead.hide-for-medium, thead.hide-for-medium-down, thead.hide-for-large-only, thead.show-for-large-up, thead.hide-for-large, thead.hide-for-large-down, thead.show-for-xlarge-only, thead.show-for-xlarge-up, thead.show-for-xlarge, thead.show-for-xlarge-down, thead.hide-for-xxlarge-only, thead.hide-for-xxlarge-up, thead.hide-for-xxlarge, thead.show-for-xxlarge-down { - display: table-header-group !important; } - - tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.hide-for-medium-only, tbody.show-for-medium-up, tbody.hide-for-medium, tbody.hide-for-medium-down, tbody.hide-for-large-only, tbody.show-for-large-up, tbody.hide-for-large, tbody.hide-for-large-down, tbody.show-for-xlarge-only, tbody.show-for-xlarge-up, tbody.show-for-xlarge, tbody.show-for-xlarge-down, tbody.hide-for-xxlarge-only, tbody.hide-for-xxlarge-up, tbody.hide-for-xxlarge, tbody.show-for-xxlarge-down { - display: table-row-group !important; } - - tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.hide-for-medium-only, tr.show-for-medium-up, tr.hide-for-medium, tr.hide-for-medium-down, tr.hide-for-large-only, tr.show-for-large-up, tr.hide-for-large, tr.hide-for-large-down, tr.show-for-xlarge-only, tr.show-for-xlarge-up, tr.show-for-xlarge, tr.show-for-xlarge-down, tr.hide-for-xxlarge-only, tr.hide-for-xxlarge-up, tr.hide-for-xxlarge, tr.show-for-xxlarge-down { - display: table-row; } - - th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.hide-for-medium-down, td.hide-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.show-for-large-up, td.show-for-large-up, th.hide-for-large, td.hide-for-large, th.hide-for-large-down, td.hide-for-large-down, th.show-for-xlarge-only, td.show-for-xlarge-only, th.show-for-xlarge-up, td.show-for-xlarge-up, th.show-for-xlarge, td.show-for-xlarge, th.show-for-xlarge-down, td.show-for-xlarge-down, th.hide-for-xxlarge-only, td.hide-for-xxlarge-only, th.hide-for-xxlarge-up, td.hide-for-xxlarge-up, th.hide-for-xxlarge, td.hide-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down { - display: table-cell !important; } } -/* xxlarge displays */ -@media only screen and (min-width: 120.0625em) { - .hide-for-small-only, .show-for-small-up, .hide-for-small, .hide-for-small-down, .hide-for-medium-only, .show-for-medium-up, .hide-for-medium, .hide-for-medium-down, .hide-for-large-only, .show-for-large-up, .hide-for-large, .hide-for-large-down, .hide-for-xlarge-only, .show-for-xlarge-up, .hide-for-xlarge, .hide-for-xlarge-down, .show-for-xxlarge-only, .show-for-xxlarge-up, .show-for-xxlarge, .show-for-xxlarge-down { - display: inherit !important; } - - .show-for-small-only, .hide-for-small-up, .show-for-small, .show-for-small-down, .show-for-medium-only, .hide-for-medium-up, .show-for-medium, .show-for-medium-down, .show-for-large-only, .hide-for-large-up, .show-for-large, .show-for-large-down, .show-for-xlarge-only, .hide-for-xlarge-up, .show-for-xlarge, .show-for-xlarge-down, .hide-for-xxlarge-only, .hide-for-xxlarge-up, .hide-for-xxlarge, .hide-for-xxlarge-down { - display: none !important; } - - .hidden-for-small-only, .visible-for-small-up, .hidden-for-small, .hidden-for-small-down, .hidden-for-medium-only, .visible-for-medium-up, .hidden-for-medium, .hidden-for-medium-down, .hidden-for-large-only, .visible-for-large-up, .hidden-for-large, .hidden-for-large-down, .hidden-for-xlarge-only, .visible-for-xlarge-up, .hidden-for-xlarge, .hidden-for-xlarge-down, .visible-for-xxlarge-only, .visible-for-xxlarge-up, .visible-for-xxlarge, .visible-for-xxlarge-down { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; } - - .visible-for-small-only, .hidden-for-small-up, .visible-for-small, .visible-for-small-down, .visible-for-medium-only, .hidden-for-medium-up, .visible-for-medium, .visible-for-medium-down, .visible-for-large-only, .hidden-for-large-up, .visible-for-large, .visible-for-large-down, .visible-for-xlarge-only, .hidden-for-xlarge-up, .visible-for-xlarge, .visible-for-xlarge-down, .hidden-for-xxlarge-only, .hidden-for-xxlarge-up, .hidden-for-xxlarge, .hidden-for-xxlarge-down { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - - table.hide-for-small-only, table.show-for-small-up, table.hide-for-small, table.hide-for-small-down, table.hide-for-medium-only, table.show-for-medium-up, table.hide-for-medium, table.hide-for-medium-down, table.hide-for-large-only, table.show-for-large-up, table.hide-for-large, table.hide-for-large-down, table.hide-for-xlarge-only, table.show-for-xlarge-up, table.hide-for-xlarge, table.hide-for-xlarge-down, table.show-for-xxlarge-only, table.show-for-xxlarge-up, table.show-for-xxlarge, table.show-for-xxlarge-down { - display: table !important; } - - thead.hide-for-small-only, thead.show-for-small-up, thead.hide-for-small, thead.hide-for-small-down, thead.hide-for-medium-only, thead.show-for-medium-up, thead.hide-for-medium, thead.hide-for-medium-down, thead.hide-for-large-only, thead.show-for-large-up, thead.hide-for-large, thead.hide-for-large-down, thead.hide-for-xlarge-only, thead.show-for-xlarge-up, thead.hide-for-xlarge, thead.hide-for-xlarge-down, thead.show-for-xxlarge-only, thead.show-for-xxlarge-up, thead.show-for-xxlarge, thead.show-for-xxlarge-down { - display: table-header-group !important; } - - tbody.hide-for-small-only, tbody.show-for-small-up, tbody.hide-for-small, tbody.hide-for-small-down, tbody.hide-for-medium-only, tbody.show-for-medium-up, tbody.hide-for-medium, tbody.hide-for-medium-down, tbody.hide-for-large-only, tbody.show-for-large-up, tbody.hide-for-large, tbody.hide-for-large-down, tbody.hide-for-xlarge-only, tbody.show-for-xlarge-up, tbody.hide-for-xlarge, tbody.hide-for-xlarge-down, tbody.show-for-xxlarge-only, tbody.show-for-xxlarge-up, tbody.show-for-xxlarge, tbody.show-for-xxlarge-down { - display: table-row-group !important; } - - tr.hide-for-small-only, tr.show-for-small-up, tr.hide-for-small, tr.hide-for-small-down, tr.hide-for-medium-only, tr.show-for-medium-up, tr.hide-for-medium, tr.hide-for-medium-down, tr.hide-for-large-only, tr.show-for-large-up, tr.hide-for-large, tr.hide-for-large-down, tr.hide-for-xlarge-only, tr.show-for-xlarge-up, tr.hide-for-xlarge, tr.hide-for-xlarge-down, tr.show-for-xxlarge-only, tr.show-for-xxlarge-up, tr.show-for-xxlarge, tr.show-for-xxlarge-down { - display: table-row; } - - th.hide-for-small-only, td.hide-for-small-only, th.show-for-small-up, td.show-for-small-up, th.hide-for-small, td.hide-for-small, th.hide-for-small-down, td.hide-for-small-down, th.hide-for-medium-only, td.hide-for-medium-only, th.show-for-medium-up, td.show-for-medium-up, th.hide-for-medium, td.hide-for-medium, th.hide-for-medium-down, td.hide-for-medium-down, th.hide-for-large-only, td.hide-for-large-only, th.show-for-large-up, td.show-for-large-up, th.hide-for-large, td.hide-for-large, th.hide-for-large-down, td.hide-for-large-down, th.hide-for-xlarge-only, td.hide-for-xlarge-only, th.show-for-xlarge-up, td.show-for-xlarge-up, th.hide-for-xlarge, td.hide-for-xlarge, th.hide-for-xlarge-down, td.hide-for-xlarge-down, th.show-for-xxlarge-only, td.show-for-xxlarge-only, th.show-for-xxlarge-up, td.show-for-xxlarge-up, th.show-for-xxlarge, td.show-for-xxlarge, th.show-for-xxlarge-down, td.show-for-xxlarge-down { - display: table-cell !important; } } -/* Orientation targeting */ -.show-for-landscape, -.hide-for-portrait { - display: inherit !important; } - -.hide-for-landscape, -.show-for-portrait { - display: none !important; } - -/* Specific visibility for tables */ -table.hide-for-landscape, table.show-for-portrait { - display: table !important; } - -thead.hide-for-landscape, thead.show-for-portrait { - display: table-header-group !important; } - -tbody.hide-for-landscape, tbody.show-for-portrait { - display: table-row-group !important; } - -tr.hide-for-landscape, tr.show-for-portrait { - display: table-row !important; } - -td.hide-for-landscape, td.show-for-portrait, -th.hide-for-landscape, -th.show-for-portrait { - display: table-cell !important; } - -@media only screen and (orientation: landscape) { - .show-for-landscape, - .hide-for-portrait { - display: inherit !important; } - - .hide-for-landscape, - .show-for-portrait { - display: none !important; } - - /* Specific visibility for tables */ - table.show-for-landscape, table.hide-for-portrait { - display: table !important; } - - thead.show-for-landscape, thead.hide-for-portrait { - display: table-header-group !important; } - - tbody.show-for-landscape, tbody.hide-for-portrait { - display: table-row-group !important; } - - tr.show-for-landscape, tr.hide-for-portrait { - display: table-row !important; } - - td.show-for-landscape, td.hide-for-portrait, - th.show-for-landscape, - th.hide-for-portrait { - display: table-cell !important; } } -@media only screen and (orientation: portrait) { - .show-for-portrait, - .hide-for-landscape { - display: inherit !important; } - - .hide-for-portrait, - .show-for-landscape { - display: none !important; } - - /* Specific visibility for tables */ - table.show-for-portrait, table.hide-for-landscape { - display: table !important; } - - thead.show-for-portrait, thead.hide-for-landscape { - display: table-header-group !important; } - - tbody.show-for-portrait, tbody.hide-for-landscape { - display: table-row-group !important; } - - tr.show-for-portrait, tr.hide-for-landscape { - display: table-row !important; } - - td.show-for-portrait, td.hide-for-landscape, - th.show-for-portrait, - th.hide-for-landscape { - display: table-cell !important; } } -/* Touch-enabled device targeting */ -.show-for-touch { - display: none !important; } - -.hide-for-touch { - display: inherit !important; } - -.touch .show-for-touch { - display: inherit !important; } - -.touch .hide-for-touch { - display: none !important; } - -/* Specific visibility for tables */ -table.hide-for-touch { - display: table !important; } - -.touch table.show-for-touch { - display: table !important; } - -thead.hide-for-touch { - display: table-header-group !important; } - -.touch thead.show-for-touch { - display: table-header-group !important; } - -tbody.hide-for-touch { - display: table-row-group !important; } - -.touch tbody.show-for-touch { - display: table-row-group !important; } - -tr.hide-for-touch { - display: table-row !important; } - -.touch tr.show-for-touch { - display: table-row !important; } - -td.hide-for-touch { - display: table-cell !important; } - -.touch td.show-for-touch { - display: table-cell !important; } - -th.hide-for-touch { - display: table-cell !important; } - -.touch th.show-for-touch { - display: table-cell !important; } - -/* Screen reader-specific classes */ -.show-for-sr { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - -.show-on-focus { - clip: rect(1px, 1px, 1px, 1px); - height: 1px; - overflow: hidden; - position: absolute !important; - width: 1px; } - .show-on-focus:focus, .show-on-focus:active { - position: static !important; - height: auto; - width: auto; - overflow: visible; - clip: auto; } - -/* Print visibility */ -.print-only, -.show-for-print { - display: none !important; } - -@media print { - .print-only, - .show-for-print { - display: block !important; } - - .hide-on-print, - .hide-for-print { - display: none !important; } - - table.show-for-print { - display: table !important; } - - thead.show-for-print { - display: table-header-group !important; } - - tbody.show-for-print { - display: table-row-group !important; } - - tr.show-for-print { - display: table-row !important; } - - td.show-for-print { - display: table-cell !important; } - - th.show-for-print { - display: table-cell !important; } } - -/*# sourceMappingURL=foundation.css.map */ - -@charset "UTF-8"; - -/*! - * animate.css -http://daneden.me/animate - * Version - 3.5.0 - * Licensed under the MIT license - http://opensource.org/licenses/MIT - * - * Copyright (c) 2016 Daniel Eden - */ - -.animated { - -webkit-animation-duration: 1s; - animation-duration: 1s; - -webkit-animation-fill-mode: both; - animation-fill-mode: both; -} - -.animated.infinite { - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; -} - -.animated.hinge { - -webkit-animation-duration: 2s; - animation-duration: 2s; -} - -.animated.flipOutX, -.animated.flipOutY, -.animated.bounceIn, -.animated.bounceOut { - -webkit-animation-duration: .75s; - animation-duration: .75s; -} - -@-webkit-keyframes bounce { - from, 20%, 53%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - -webkit-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); - } - - 40%, 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0,-4px,0); - transform: translate3d(0,-4px,0); - } -} - -@keyframes bounce { - from, 20%, 53%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - -webkit-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); - } - - 40%, 43% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -30px, 0); - transform: translate3d(0, -30px, 0); - } - - 70% { - -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060); - -webkit-transform: translate3d(0, -15px, 0); - transform: translate3d(0, -15px, 0); - } - - 90% { - -webkit-transform: translate3d(0,-4px,0); - transform: translate3d(0,-4px,0); - } -} - -.bounce { - -webkit-animation-name: bounce; - animation-name: bounce; - -webkit-transform-origin: center bottom; - transform-origin: center bottom; -} - -@-webkit-keyframes flash { - from, 50%, to { - opacity: 1; - } - - 25%, 75% { - opacity: 0; - } -} - -@keyframes flash { - from, 50%, to { - opacity: 1; - } - - 25%, 75% { - opacity: 0; - } -} - -.flash { - -webkit-animation-name: flash; - animation-name: flash; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes pulse { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 50% { - -webkit-transform: scale3d(1.05, 1.05, 1.05); - transform: scale3d(1.05, 1.05, 1.05); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes pulse { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 50% { - -webkit-transform: scale3d(1.05, 1.05, 1.05); - transform: scale3d(1.05, 1.05, 1.05); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.pulse { - -webkit-animation-name: pulse; - animation-name: pulse; -} - -@-webkit-keyframes rubberBand { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 30% { - -webkit-transform: scale3d(1.25, 0.75, 1); - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - -webkit-transform: scale3d(0.75, 1.25, 1); - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - -webkit-transform: scale3d(1.15, 0.85, 1); - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - -webkit-transform: scale3d(.95, 1.05, 1); - transform: scale3d(.95, 1.05, 1); - } - - 75% { - -webkit-transform: scale3d(1.05, .95, 1); - transform: scale3d(1.05, .95, 1); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes rubberBand { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 30% { - -webkit-transform: scale3d(1.25, 0.75, 1); - transform: scale3d(1.25, 0.75, 1); - } - - 40% { - -webkit-transform: scale3d(0.75, 1.25, 1); - transform: scale3d(0.75, 1.25, 1); - } - - 50% { - -webkit-transform: scale3d(1.15, 0.85, 1); - transform: scale3d(1.15, 0.85, 1); - } - - 65% { - -webkit-transform: scale3d(.95, 1.05, 1); - transform: scale3d(.95, 1.05, 1); - } - - 75% { - -webkit-transform: scale3d(1.05, .95, 1); - transform: scale3d(1.05, .95, 1); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.rubberBand { - -webkit-animation-name: rubberBand; - animation-name: rubberBand; -} - -@-webkit-keyframes shake { - from, to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, 30%, 50%, 70%, 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, 40%, 60%, 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -@keyframes shake { - from, to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - 10%, 30%, 50%, 70%, 90% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 20%, 40%, 60%, 80% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } -} - -.shake { - -webkit-animation-name: shake; - animation-name: shake; -} - -@-webkit-keyframes headShake { - 0% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - - 6.5% { - -webkit-transform: translateX(-6px) rotateY(-9deg); - transform: translateX(-6px) rotateY(-9deg); - } - - 18.5% { - -webkit-transform: translateX(5px) rotateY(7deg); - transform: translateX(5px) rotateY(7deg); - } - - 31.5% { - -webkit-transform: translateX(-3px) rotateY(-5deg); - transform: translateX(-3px) rotateY(-5deg); - } - - 43.5% { - -webkit-transform: translateX(2px) rotateY(3deg); - transform: translateX(2px) rotateY(3deg); - } - - 50% { - -webkit-transform: translateX(0); - transform: translateX(0); - } -} - -@keyframes headShake { - 0% { - -webkit-transform: translateX(0); - transform: translateX(0); - } - - 6.5% { - -webkit-transform: translateX(-6px) rotateY(-9deg); - transform: translateX(-6px) rotateY(-9deg); - } - - 18.5% { - -webkit-transform: translateX(5px) rotateY(7deg); - transform: translateX(5px) rotateY(7deg); - } - - 31.5% { - -webkit-transform: translateX(-3px) rotateY(-5deg); - transform: translateX(-3px) rotateY(-5deg); - } - - 43.5% { - -webkit-transform: translateX(2px) rotateY(3deg); - transform: translateX(2px) rotateY(3deg); - } - - 50% { - -webkit-transform: translateX(0); - transform: translateX(0); - } -} - -.headShake { - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - -webkit-animation-name: headShake; - animation-name: headShake; -} - -@-webkit-keyframes swing { - 20% { - -webkit-transform: rotate3d(0, 0, 1, 15deg); - transform: rotate3d(0, 0, 1, 15deg); - } - - 40% { - -webkit-transform: rotate3d(0, 0, 1, -10deg); - transform: rotate3d(0, 0, 1, -10deg); - } - - 60% { - -webkit-transform: rotate3d(0, 0, 1, 5deg); - transform: rotate3d(0, 0, 1, 5deg); - } - - 80% { - -webkit-transform: rotate3d(0, 0, 1, -5deg); - transform: rotate3d(0, 0, 1, -5deg); - } - - to { - -webkit-transform: rotate3d(0, 0, 1, 0deg); - transform: rotate3d(0, 0, 1, 0deg); - } -} - -@keyframes swing { - 20% { - -webkit-transform: rotate3d(0, 0, 1, 15deg); - transform: rotate3d(0, 0, 1, 15deg); - } - - 40% { - -webkit-transform: rotate3d(0, 0, 1, -10deg); - transform: rotate3d(0, 0, 1, -10deg); - } - - 60% { - -webkit-transform: rotate3d(0, 0, 1, 5deg); - transform: rotate3d(0, 0, 1, 5deg); - } - - 80% { - -webkit-transform: rotate3d(0, 0, 1, -5deg); - transform: rotate3d(0, 0, 1, -5deg); - } - - to { - -webkit-transform: rotate3d(0, 0, 1, 0deg); - transform: rotate3d(0, 0, 1, 0deg); - } -} - -.swing { - -webkit-transform-origin: top center; - transform-origin: top center; - -webkit-animation-name: swing; - animation-name: swing; -} - -@-webkit-keyframes tada { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 10%, 20% { - -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - } - - 30%, 50%, 70%, 90% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, 60%, 80% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes tada { - from { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } - - 10%, 20% { - -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg); - } - - 30%, 50%, 70%, 90% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); - } - - 40%, 60%, 80% { - -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); - } - - to { - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.tada { - -webkit-animation-name: tada; - animation-name: tada; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes wobble { - from { - -webkit-transform: none; - transform: none; - } - - 15% { - -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - } - - 30% { - -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - } - - 45% { - -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - } - - 60% { - -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - } - - 75% { - -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes wobble { - from { - -webkit-transform: none; - transform: none; - } - - 15% { - -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); - } - - 30% { - -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); - } - - 45% { - -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); - } - - 60% { - -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); - } - - 75% { - -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.wobble { - -webkit-animation-name: wobble; - animation-name: wobble; -} - -@-webkit-keyframes jello { - from, 11.1%, to { - -webkit-transform: none; - transform: none; - } - - 22.2% { - -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); - transform: skewX(-12.5deg) skewY(-12.5deg); - } - - 33.3% { - -webkit-transform: skewX(6.25deg) skewY(6.25deg); - transform: skewX(6.25deg) skewY(6.25deg); - } - - 44.4% { - -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); - transform: skewX(-3.125deg) skewY(-3.125deg); - } - - 55.5% { - -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); - transform: skewX(1.5625deg) skewY(1.5625deg); - } - - 66.6% { - -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); - transform: skewX(-0.78125deg) skewY(-0.78125deg); - } - - 77.7% { - -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); - transform: skewX(0.390625deg) skewY(0.390625deg); - } - - 88.8% { - -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - } -} - -@keyframes jello { - from, 11.1%, to { - -webkit-transform: none; - transform: none; - } - - 22.2% { - -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); - transform: skewX(-12.5deg) skewY(-12.5deg); - } - - 33.3% { - -webkit-transform: skewX(6.25deg) skewY(6.25deg); - transform: skewX(6.25deg) skewY(6.25deg); - } - - 44.4% { - -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); - transform: skewX(-3.125deg) skewY(-3.125deg); - } - - 55.5% { - -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); - transform: skewX(1.5625deg) skewY(1.5625deg); - } - - 66.6% { - -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); - transform: skewX(-0.78125deg) skewY(-0.78125deg); - } - - 77.7% { - -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); - transform: skewX(0.390625deg) skewY(0.390625deg); - } - - 88.8% { - -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - transform: skewX(-0.1953125deg) skewY(-0.1953125deg); - } -} - -.jello { - -webkit-animation-name: jello; - animation-name: jello; - -webkit-transform-origin: center; - transform-origin: center; -} - -@-webkit-keyframes bounceIn { - from, 20%, 40%, 60%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 20% { - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - 40% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(1.03, 1.03, 1.03); - transform: scale3d(1.03, 1.03, 1.03); - } - - 80% { - -webkit-transform: scale3d(.97, .97, .97); - transform: scale3d(.97, .97, .97); - } - - to { - opacity: 1; - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -@keyframes bounceIn { - from, 20%, 40%, 60%, 80%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 20% { - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - 40% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(1.03, 1.03, 1.03); - transform: scale3d(1.03, 1.03, 1.03); - } - - 80% { - -webkit-transform: scale3d(.97, .97, .97); - transform: scale3d(.97, .97, .97); - } - - to { - opacity: 1; - -webkit-transform: scale3d(1, 1, 1); - transform: scale3d(1, 1, 1); - } -} - -.bounceIn { - -webkit-animation-name: bounceIn; - animation-name: bounceIn; -} - -@-webkit-keyframes bounceInDown { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -3000px, 0); - transform: translate3d(0, -3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, 25px, 0); - transform: translate3d(0, 25px, 0); - } - - 75% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, 5px, 0); - transform: translate3d(0, 5px, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes bounceInDown { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(0, -3000px, 0); - transform: translate3d(0, -3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, 25px, 0); - transform: translate3d(0, 25px, 0); - } - - 75% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, 5px, 0); - transform: translate3d(0, 5px, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.bounceInDown { - -webkit-animation-name: bounceInDown; - animation-name: bounceInDown; -} - -@-webkit-keyframes bounceInLeft { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(-3000px, 0, 0); - transform: translate3d(-3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(25px, 0, 0); - transform: translate3d(25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(5px, 0, 0); - transform: translate3d(5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes bounceInLeft { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - 0% { - opacity: 0; - -webkit-transform: translate3d(-3000px, 0, 0); - transform: translate3d(-3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(25px, 0, 0); - transform: translate3d(25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(-10px, 0, 0); - transform: translate3d(-10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(5px, 0, 0); - transform: translate3d(5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.bounceInLeft { - -webkit-animation-name: bounceInLeft; - animation-name: bounceInLeft; -} - -@-webkit-keyframes bounceInRight { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(3000px, 0, 0); - transform: translate3d(3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(-25px, 0, 0); - transform: translate3d(-25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(-5px, 0, 0); - transform: translate3d(-5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -@keyframes bounceInRight { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(3000px, 0, 0); - transform: translate3d(3000px, 0, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(-25px, 0, 0); - transform: translate3d(-25px, 0, 0); - } - - 75% { - -webkit-transform: translate3d(10px, 0, 0); - transform: translate3d(10px, 0, 0); - } - - 90% { - -webkit-transform: translate3d(-5px, 0, 0); - transform: translate3d(-5px, 0, 0); - } - - to { - -webkit-transform: none; - transform: none; - } -} - -.bounceInRight { - -webkit-animation-name: bounceInRight; - animation-name: bounceInRight; -} - -@-webkit-keyframes bounceInUp { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(0, 3000px, 0); - transform: translate3d(0, 3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - 75% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -5px, 0); - transform: translate3d(0, -5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes bounceInUp { - from, 60%, 75%, 90%, to { - -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); - } - - from { - opacity: 0; - -webkit-transform: translate3d(0, 3000px, 0); - transform: translate3d(0, 3000px, 0); - } - - 60% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - 75% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 90% { - -webkit-transform: translate3d(0, -5px, 0); - transform: translate3d(0, -5px, 0); - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.bounceInUp { - -webkit-animation-name: bounceInUp; - animation-name: bounceInUp; -} - -@-webkit-keyframes bounceOut { - 20% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 50%, 55% { - opacity: 1; - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } -} - -@keyframes bounceOut { - 20% { - -webkit-transform: scale3d(.9, .9, .9); - transform: scale3d(.9, .9, .9); - } - - 50%, 55% { - opacity: 1; - -webkit-transform: scale3d(1.1, 1.1, 1.1); - transform: scale3d(1.1, 1.1, 1.1); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } -} - -.bounceOut { - -webkit-animation-name: bounceOut; - animation-name: bounceOut; -} - -@-webkit-keyframes bounceOutDown { - 20% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -@keyframes bounceOutDown { - 20% { - -webkit-transform: translate3d(0, 10px, 0); - transform: translate3d(0, 10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, -20px, 0); - transform: translate3d(0, -20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -.bounceOutDown { - -webkit-animation-name: bounceOutDown; - animation-name: bounceOutDown; -} - -@-webkit-keyframes bounceOutLeft { - 20% { - opacity: 1; - -webkit-transform: translate3d(20px, 0, 0); - transform: translate3d(20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -@keyframes bounceOutLeft { - 20% { - opacity: 1; - -webkit-transform: translate3d(20px, 0, 0); - transform: translate3d(20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -.bounceOutLeft { - -webkit-animation-name: bounceOutLeft; - animation-name: bounceOutLeft; -} - -@-webkit-keyframes bounceOutRight { - 20% { - opacity: 1; - -webkit-transform: translate3d(-20px, 0, 0); - transform: translate3d(-20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -@keyframes bounceOutRight { - 20% { - opacity: 1; - -webkit-transform: translate3d(-20px, 0, 0); - transform: translate3d(-20px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -.bounceOutRight { - -webkit-animation-name: bounceOutRight; - animation-name: bounceOutRight; -} - -@-webkit-keyframes bounceOutUp { - 20% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, 20px, 0); - transform: translate3d(0, 20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -@keyframes bounceOutUp { - 20% { - -webkit-transform: translate3d(0, -10px, 0); - transform: translate3d(0, -10px, 0); - } - - 40%, 45% { - opacity: 1; - -webkit-transform: translate3d(0, 20px, 0); - transform: translate3d(0, 20px, 0); - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -.bounceOutUp { - -webkit-animation-name: bounceOutUp; - animation-name: bounceOutUp; -} - -@-webkit-keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -.fadeIn { - -webkit-animation-name: fadeIn; - animation-name: fadeIn; -} - -@-webkit-keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDown { - from { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInDown { - -webkit-animation-name: fadeInDown; - animation-name: fadeInDown; -} - -@-webkit-keyframes fadeInDownBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInDownBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInDownBig { - -webkit-animation-name: fadeInDownBig; - animation-name: fadeInDownBig; -} - -@-webkit-keyframes fadeInLeft { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInLeft { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInLeft { - -webkit-animation-name: fadeInLeft; - animation-name: fadeInLeft; -} - -@-webkit-keyframes fadeInLeftBig { - from { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInLeftBig { - from { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInLeftBig { - -webkit-animation-name: fadeInLeftBig; - animation-name: fadeInLeftBig; -} - -@-webkit-keyframes fadeInRight { - from { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInRight { - from { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInRight { - -webkit-animation-name: fadeInRight; - animation-name: fadeInRight; -} - -@-webkit-keyframes fadeInRightBig { - from { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInRightBig { - from { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInRightBig { - -webkit-animation-name: fadeInRightBig; - animation-name: fadeInRightBig; -} - -@-webkit-keyframes fadeInUp { - from { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInUp { - from { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInUp { - -webkit-animation-name: fadeInUp; - animation-name: fadeInUp; -} - -@-webkit-keyframes fadeInUpBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes fadeInUpBig { - from { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.fadeInUpBig { - -webkit-animation-name: fadeInUpBig; - animation-name: fadeInUpBig; -} - -@-webkit-keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -@keyframes fadeOut { - from { - opacity: 1; - } - - to { - opacity: 0; - } -} - -.fadeOut { - -webkit-animation-name: fadeOut; - animation-name: fadeOut; -} - -@-webkit-keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes fadeOutDown { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.fadeOutDown { - -webkit-animation-name: fadeOutDown; - animation-name: fadeOutDown; -} - -@-webkit-keyframes fadeOutDownBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -@keyframes fadeOutDownBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, 2000px, 0); - transform: translate3d(0, 2000px, 0); - } -} - -.fadeOutDownBig { - -webkit-animation-name: fadeOutDownBig; - animation-name: fadeOutDownBig; -} - -@-webkit-keyframes fadeOutLeft { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes fadeOutLeft { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.fadeOutLeft { - -webkit-animation-name: fadeOutLeft; - animation-name: fadeOutLeft; -} - -@-webkit-keyframes fadeOutLeftBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -@keyframes fadeOutLeftBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(-2000px, 0, 0); - transform: translate3d(-2000px, 0, 0); - } -} - -.fadeOutLeftBig { - -webkit-animation-name: fadeOutLeftBig; - animation-name: fadeOutLeftBig; -} - -@-webkit-keyframes fadeOutRight { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@keyframes fadeOutRight { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.fadeOutRight { - -webkit-animation-name: fadeOutRight; - animation-name: fadeOutRight; -} - -@-webkit-keyframes fadeOutRightBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -@keyframes fadeOutRightBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(2000px, 0, 0); - transform: translate3d(2000px, 0, 0); - } -} - -.fadeOutRightBig { - -webkit-animation-name: fadeOutRightBig; - animation-name: fadeOutRightBig; -} - -@-webkit-keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes fadeOutUp { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.fadeOutUp { - -webkit-animation-name: fadeOutUp; - animation-name: fadeOutUp; -} - -@-webkit-keyframes fadeOutUpBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -@keyframes fadeOutUpBig { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(0, -2000px, 0); - transform: translate3d(0, -2000px, 0); - } -} - -.fadeOutUpBig { - -webkit-animation-name: fadeOutUpBig; - animation-name: fadeOutUpBig; -} - -@-webkit-keyframes flip { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 40% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 50% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 80% { - -webkit-transform: perspective(400px) scale3d(.95, .95, .95); - transform: perspective(400px) scale3d(.95, .95, .95); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } -} - -@keyframes flip { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - transform: perspective(400px) rotate3d(0, 1, 0, -360deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 40% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; - } - - 50% { - -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 80% { - -webkit-transform: perspective(400px) scale3d(.95, .95, .95); - transform: perspective(400px) scale3d(.95, .95, .95); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } -} - -.animated.flip { - -webkit-backface-visibility: visible; - backface-visibility: visible; - -webkit-animation-name: flip; - animation-name: flip; -} - -@-webkit-keyframes flipInX { - from { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -@keyframes flipInX { - from { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - transform: perspective(400px) rotate3d(1, 0, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - transform: perspective(400px) rotate3d(1, 0, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -.flipInX { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipInX; - animation-name: flipInX; -} - -@-webkit-keyframes flipInY { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -@keyframes flipInY { - from { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - opacity: 0; - } - - 40% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - transform: perspective(400px) rotate3d(0, 1, 0, -20deg); - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; - } - - 60% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - transform: perspective(400px) rotate3d(0, 1, 0, 10deg); - opacity: 1; - } - - 80% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - transform: perspective(400px) rotate3d(0, 1, 0, -5deg); - } - - to { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } -} - -.flipInY { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipInY; - animation-name: flipInY; -} - -@-webkit-keyframes flipOutX { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - opacity: 0; - } -} - -@keyframes flipOutX { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - transform: perspective(400px) rotate3d(1, 0, 0, -20deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - transform: perspective(400px) rotate3d(1, 0, 0, 90deg); - opacity: 0; - } -} - -.flipOutX { - -webkit-animation-name: flipOutX; - animation-name: flipOutX; - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; -} - -@-webkit-keyframes flipOutY { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - opacity: 0; - } -} - -@keyframes flipOutY { - from { - -webkit-transform: perspective(400px); - transform: perspective(400px); - } - - 30% { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - transform: perspective(400px) rotate3d(0, 1, 0, -15deg); - opacity: 1; - } - - to { - -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - transform: perspective(400px) rotate3d(0, 1, 0, 90deg); - opacity: 0; - } -} - -.flipOutY { - -webkit-backface-visibility: visible !important; - backface-visibility: visible !important; - -webkit-animation-name: flipOutY; - animation-name: flipOutY; -} - -@-webkit-keyframes lightSpeedIn { - from { - -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); - transform: translate3d(100%, 0, 0) skewX(-30deg); - opacity: 0; - } - - 60% { - -webkit-transform: skewX(20deg); - transform: skewX(20deg); - opacity: 1; - } - - 80% { - -webkit-transform: skewX(-5deg); - transform: skewX(-5deg); - opacity: 1; - } - - to { - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes lightSpeedIn { - from { - -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); - transform: translate3d(100%, 0, 0) skewX(-30deg); - opacity: 0; - } - - 60% { - -webkit-transform: skewX(20deg); - transform: skewX(20deg); - opacity: 1; - } - - 80% { - -webkit-transform: skewX(-5deg); - transform: skewX(-5deg); - opacity: 1; - } - - to { - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.lightSpeedIn { - -webkit-animation-name: lightSpeedIn; - animation-name: lightSpeedIn; - -webkit-animation-timing-function: ease-out; - animation-timing-function: ease-out; -} - -@-webkit-keyframes lightSpeedOut { - from { - opacity: 1; - } - - to { - -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); - transform: translate3d(100%, 0, 0) skewX(30deg); - opacity: 0; - } -} - -@keyframes lightSpeedOut { - from { - opacity: 1; - } - - to { - -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); - transform: translate3d(100%, 0, 0) skewX(30deg); - opacity: 0; - } -} - -.lightSpeedOut { - -webkit-animation-name: lightSpeedOut; - animation-name: lightSpeedOut; - -webkit-animation-timing-function: ease-in; - animation-timing-function: ease-in; -} - -@-webkit-keyframes rotateIn { - from { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, -200deg); - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateIn { - from { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, -200deg); - transform: rotate3d(0, 0, 1, -200deg); - opacity: 0; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateIn { - -webkit-animation-name: rotateIn; - animation-name: rotateIn; -} - -@-webkit-keyframes rotateInDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInDownLeft { - -webkit-animation-name: rotateInDownLeft; - animation-name: rotateInDownLeft; -} - -@-webkit-keyframes rotateInDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInDownRight { - -webkit-animation-name: rotateInDownRight; - animation-name: rotateInDownRight; -} - -@-webkit-keyframes rotateInUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInUpLeft { - -webkit-animation-name: rotateInUpLeft; - animation-name: rotateInUpLeft; -} - -@-webkit-keyframes rotateInUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -90deg); - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -@keyframes rotateInUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -90deg); - transform: rotate3d(0, 0, 1, -90deg); - opacity: 0; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: none; - transform: none; - opacity: 1; - } -} - -.rotateInUpRight { - -webkit-animation-name: rotateInUpRight; - animation-name: rotateInUpRight; -} - -@-webkit-keyframes rotateOut { - from { - -webkit-transform-origin: center; - transform-origin: center; - opacity: 1; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, 200deg); - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} - -@keyframes rotateOut { - from { - -webkit-transform-origin: center; - transform-origin: center; - opacity: 1; - } - - to { - -webkit-transform-origin: center; - transform-origin: center; - -webkit-transform: rotate3d(0, 0, 1, 200deg); - transform: rotate3d(0, 0, 1, 200deg); - opacity: 0; - } -} - -.rotateOut { - -webkit-animation-name: rotateOut; - animation-name: rotateOut; -} - -@-webkit-keyframes rotateOutDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} - -@keyframes rotateOutDownLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, 45deg); - transform: rotate3d(0, 0, 1, 45deg); - opacity: 0; - } -} - -.rotateOutDownLeft { - -webkit-animation-name: rotateOutDownLeft; - animation-name: rotateOutDownLeft; -} - -@-webkit-keyframes rotateOutDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -@keyframes rotateOutDownRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -.rotateOutDownRight { - -webkit-animation-name: rotateOutDownRight; - animation-name: rotateOutDownRight; -} - -@-webkit-keyframes rotateOutUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -@keyframes rotateOutUpLeft { - from { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: left bottom; - transform-origin: left bottom; - -webkit-transform: rotate3d(0, 0, 1, -45deg); - transform: rotate3d(0, 0, 1, -45deg); - opacity: 0; - } -} - -.rotateOutUpLeft { - -webkit-animation-name: rotateOutUpLeft; - animation-name: rotateOutUpLeft; -} - -@-webkit-keyframes rotateOutUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 90deg); - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} - -@keyframes rotateOutUpRight { - from { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - opacity: 1; - } - - to { - -webkit-transform-origin: right bottom; - transform-origin: right bottom; - -webkit-transform: rotate3d(0, 0, 1, 90deg); - transform: rotate3d(0, 0, 1, 90deg); - opacity: 0; - } -} - -.rotateOutUpRight { - -webkit-animation-name: rotateOutUpRight; - animation-name: rotateOutUpRight; -} - -@-webkit-keyframes hinge { - 0% { - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 20%, 60% { - -webkit-transform: rotate3d(0, 0, 1, 80deg); - transform: rotate3d(0, 0, 1, 80deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 40%, 80% { - -webkit-transform: rotate3d(0, 0, 1, 60deg); - transform: rotate3d(0, 0, 1, 60deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 700px, 0); - transform: translate3d(0, 700px, 0); - opacity: 0; - } -} - -@keyframes hinge { - 0% { - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 20%, 60% { - -webkit-transform: rotate3d(0, 0, 1, 80deg); - transform: rotate3d(0, 0, 1, 80deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - } - - 40%, 80% { - -webkit-transform: rotate3d(0, 0, 1, 60deg); - transform: rotate3d(0, 0, 1, 60deg); - -webkit-transform-origin: top left; - transform-origin: top left; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - opacity: 1; - } - - to { - -webkit-transform: translate3d(0, 700px, 0); - transform: translate3d(0, 700px, 0); - opacity: 0; - } -} - -.hinge { - -webkit-animation-name: hinge; - animation-name: hinge; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes rollIn { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -@keyframes rollIn { - from { - opacity: 0; - -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); - } - - to { - opacity: 1; - -webkit-transform: none; - transform: none; - } -} - -.rollIn { - -webkit-animation-name: rollIn; - animation-name: rollIn; -} - -/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ - -@-webkit-keyframes rollOut { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - } -} - -@keyframes rollOut { - from { - opacity: 1; - } - - to { - opacity: 0; - -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); - } -} - -.rollOut { - -webkit-animation-name: rollOut; - animation-name: rollOut; -} - -@-webkit-keyframes zoomIn { - from { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 50% { - opacity: 1; - } -} - -@keyframes zoomIn { - from { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - 50% { - opacity: 1; - } -} - -.zoomIn { - -webkit-animation-name: zoomIn; - animation-name: zoomIn; -} - -@-webkit-keyframes zoomInDown { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInDown { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInDown { - -webkit-animation-name: zoomInDown; - animation-name: zoomInDown; -} - -@-webkit-keyframes zoomInLeft { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInLeft { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInLeft { - -webkit-animation-name: zoomInLeft; - animation-name: zoomInLeft; -} - -@-webkit-keyframes zoomInRight { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInRight { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInRight { - -webkit-animation-name: zoomInRight; - animation-name: zoomInRight; -} - -@-webkit-keyframes zoomInUp { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomInUp { - from { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - 60% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomInUp { - -webkit-animation-name: zoomInUp; - animation-name: zoomInUp; -} - -@-webkit-keyframes zoomOut { - from { - opacity: 1; - } - - 50% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - to { - opacity: 0; - } -} - -@keyframes zoomOut { - from { - opacity: 1; - } - - 50% { - opacity: 0; - -webkit-transform: scale3d(.3, .3, .3); - transform: scale3d(.3, .3, .3); - } - - to { - opacity: 0; - } -} - -.zoomOut { - -webkit-animation-name: zoomOut; - animation-name: zoomOut; -} - -@-webkit-keyframes zoomOutDown { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomOutDown { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomOutDown { - -webkit-animation-name: zoomOutDown; - animation-name: zoomOutDown; -} - -@-webkit-keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); - transform: scale(.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -@keyframes zoomOutLeft { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(-2000px, 0, 0); - transform: scale(.1) translate3d(-2000px, 0, 0); - -webkit-transform-origin: left center; - transform-origin: left center; - } -} - -.zoomOutLeft { - -webkit-animation-name: zoomOutLeft; - animation-name: zoomOutLeft; -} - -@-webkit-keyframes zoomOutRight { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(2000px, 0, 0); - transform: scale(.1) translate3d(2000px, 0, 0); - -webkit-transform-origin: right center; - transform-origin: right center; - } -} - -@keyframes zoomOutRight { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0); - } - - to { - opacity: 0; - -webkit-transform: scale(.1) translate3d(2000px, 0, 0); - transform: scale(.1) translate3d(2000px, 0, 0); - -webkit-transform-origin: right center; - transform-origin: right center; - } -} - -.zoomOutRight { - -webkit-animation-name: zoomOutRight; - animation-name: zoomOutRight; -} - -@-webkit-keyframes zoomOutUp { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -@keyframes zoomOutUp { - 40% { - opacity: 1; - -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0); - -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190); - } - - to { - opacity: 0; - -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0); - -webkit-transform-origin: center bottom; - transform-origin: center bottom; - -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); - } -} - -.zoomOutUp { - -webkit-animation-name: zoomOutUp; - animation-name: zoomOutUp; -} - -@-webkit-keyframes slideInDown { - from { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInDown { - from { - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInDown { - -webkit-animation-name: slideInDown; - animation-name: slideInDown; -} - -@-webkit-keyframes slideInLeft { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInLeft { - from { - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInLeft { - -webkit-animation-name: slideInLeft; - animation-name: slideInLeft; -} - -@-webkit-keyframes slideInRight { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInRight { - from { - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInRight { - -webkit-animation-name: slideInRight; - animation-name: slideInRight; -} - -@-webkit-keyframes slideInUp { - from { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -@keyframes slideInUp { - from { - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - visibility: visible; - } - - to { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} - -.slideInUp { - -webkit-animation-name: slideInUp; - animation-name: slideInUp; -} - -@-webkit-keyframes slideOutDown { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -@keyframes slideOutDown { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} - -.slideOutDown { - -webkit-animation-name: slideOutDown; - animation-name: slideOutDown; -} - -@-webkit-keyframes slideOutLeft { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes slideOutLeft { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } -} - -.slideOutLeft { - -webkit-animation-name: slideOutLeft; - animation-name: slideOutLeft; -} - -@-webkit-keyframes slideOutRight { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -@keyframes slideOutRight { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } -} - -.slideOutRight { - -webkit-animation-name: slideOutRight; - animation-name: slideOutRight; -} - -@-webkit-keyframes slideOutUp { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -@keyframes slideOutUp { - from { - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } - - to { - visibility: hidden; - -webkit-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); - } -} - -.slideOutUp { - -webkit-animation-name: slideOutUp; - animation-name: slideOutUp; -} diff --git a/browser-extensions/chrome/copay-chrome-extension/css/ionic.css b/browser-extensions/chrome/copay-chrome-extension/css/ionic.css deleted file mode 100644 index 5dddf272b..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/css/ionic.css +++ /dev/null @@ -1,23 +0,0 @@ -@charset "UTF-8";/*! - * Copyright 2015 Drifty Co. - * http://drifty.com/ - * - * Ionic, v1.3.1 - * A powerful HTML5 mobile app framework. - * http://ionicframework.com/ - * - * By @maxlynch, @benjsperry, @adamdbradley <3 - * - * Licensed under the MIT license. Please see LICENSE for more information. - * - *//*! - Ionicons, v2.0.1 - Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ - https://twitter.com/benjsperry https://twitter.com/ionicframework - MIT License: https://github.com/driftyco/ionicons - - Android-style icons originally built by Google’s - Material Design Icons: https://github.com/google/material-design-icons - used under CC BY http://creativecommons.org/licenses/by/4.0/ - Modified icons to fit ionicon’s grid from original. -*/@font-face{font-family:Ionicons;src:url(../fonts/ionicons.eot?v=2.0.1);src:url(../fonts/ionicons.eot?v=2.0.1#iefix) format("embedded-opentype"),url(../fonts/ionicons.ttf?v=2.0.1) format("truetype"),url(../fonts/ionicons.woff?v=2.0.1) format("woff"),url(../fonts/ionicons.woff) format("woff"),url(../fonts/ionicons.svg?v=2.0.1#Ionicons) format("svg");font-weight:400;font-style:normal}.ion,.ion-alert-circled:before,.ion-alert:before,.ion-android-add-circle:before,.ion-android-add:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-cloud:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done-all:before,.ion-android-done:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite-outline:before,.ion-android-favorite:before,.ion-android-film:before,.ion-android-folder-open:before,.ion-android-folder:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone-off:before,.ion-android-microphone:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-notifications:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person-add:before,.ion-android-person:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove-circle:before,.ion-android-remove:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share-alt:before,.ion-android-share:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-star:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace-outline:before,.ion-backspace:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox-working:before,.ion-chatbox:before,.ion-chatboxes:before,.ion-chatbubble-working:before,.ion-chatbubble:before,.ion-chatbubbles:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-checkmark:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close-circled:before,.ion-close-round:before,.ion-close:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code-download:before,.ion-code-working:before,.ion-code:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document-text:before,.ion-document:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email-unread:before,.ion-email:before,.ion-erlenmeyer-flask-bubbles:before,.ion-erlenmeyer-flask:before,.ion-eye-disabled:before,.ion-eye:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash-off:before,.ion-flash:before,.ion-folder:before,.ion-fork-repo:before,.ion-fork:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy-outline:before,.ion-happy:before,.ion-headphone:before,.ion-heart-broken:before,.ion-heart:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-help:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information-circled:before,.ion-information:before,.ion-ionic:before,.ion-ios-alarm-outline:before,.ion-ios-alarm:before,.ion-ios-albums-outline:before,.ion-ios-albums:before,.ion-ios-americanfootball-outline:before,.ion-ios-americanfootball:before,.ion-ios-analytics-outline:before,.ion-ios-analytics:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at-outline:before,.ion-ios-at:before,.ion-ios-barcode-outline:before,.ion-ios-barcode:before,.ion-ios-baseball-outline:before,.ion-ios-baseball:before,.ion-ios-basketball-outline:before,.ion-ios-basketball:before,.ion-ios-bell-outline:before,.ion-ios-bell:before,.ion-ios-body-outline:before,.ion-ios-body:before,.ion-ios-bolt-outline:before,.ion-ios-bolt:before,.ion-ios-book-outline:before,.ion-ios-book:before,.ion-ios-bookmarks-outline:before,.ion-ios-bookmarks:before,.ion-ios-box-outline:before,.ion-ios-box:before,.ion-ios-briefcase-outline:before,.ion-ios-briefcase:before,.ion-ios-browsers-outline:before,.ion-ios-browsers:before,.ion-ios-calculator-outline:before,.ion-ios-calculator:before,.ion-ios-calendar-outline:before,.ion-ios-calendar:before,.ion-ios-camera-outline:before,.ion-ios-camera:before,.ion-ios-cart-outline:before,.ion-ios-cart:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatbubble-outline:before,.ion-ios-chatbubble:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-checkmark:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock-outline:before,.ion-ios-clock:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-close:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-download:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-outline:before,.ion-ios-cloudy:before,.ion-ios-cog-outline:before,.ion-ios-cog:before,.ion-ios-color-filter-outline:before,.ion-ios-color-filter:before,.ion-ios-color-wand-outline:before,.ion-ios-color-wand:before,.ion-ios-compose-outline:before,.ion-ios-compose:before,.ion-ios-contact-outline:before,.ion-ios-contact:before,.ion-ios-copy-outline:before,.ion-ios-copy:before,.ion-ios-crop-strong:before,.ion-ios-crop:before,.ion-ios-download-outline:before,.ion-ios-download:before,.ion-ios-drag:before,.ion-ios-email-outline:before,.ion-ios-email:before,.ion-ios-eye-outline:before,.ion-ios-eye:before,.ion-ios-fastforward-outline:before,.ion-ios-fastforward:before,.ion-ios-filing-outline:before,.ion-ios-filing:before,.ion-ios-film-outline:before,.ion-ios-film:before,.ion-ios-flag-outline:before,.ion-ios-flag:before,.ion-ios-flame-outline:before,.ion-ios-flame:before,.ion-ios-flask-outline:before,.ion-ios-flask:before,.ion-ios-flower-outline:before,.ion-ios-flower:before,.ion-ios-folder-outline:before,.ion-ios-folder:before,.ion-ios-football-outline:before,.ion-ios-football:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-b-outline:before,.ion-ios-game-controller-b:before,.ion-ios-gear-outline:before,.ion-ios-gear:before,.ion-ios-glasses-outline:before,.ion-ios-glasses:before,.ion-ios-grid-view-outline:before,.ion-ios-grid-view:before,.ion-ios-heart-outline:before,.ion-ios-heart:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-help:before,.ion-ios-home-outline:before,.ion-ios-home:before,.ion-ios-infinite-outline:before,.ion-ios-infinite:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-information:before,.ion-ios-ionic-outline:before,.ion-ios-keypad-outline:before,.ion-ios-keypad:before,.ion-ios-lightbulb-outline:before,.ion-ios-lightbulb:before,.ion-ios-list-outline:before,.ion-ios-list:before,.ion-ios-location-outline:before,.ion-ios-location:before,.ion-ios-locked-outline:before,.ion-ios-locked:before,.ion-ios-loop-strong:before,.ion-ios-loop:before,.ion-ios-medical-outline:before,.ion-ios-medical:before,.ion-ios-medkit-outline:before,.ion-ios-medkit:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-mic:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-minus:before,.ion-ios-monitor-outline:before,.ion-ios-monitor:before,.ion-ios-moon-outline:before,.ion-ios-moon:before,.ion-ios-more-outline:before,.ion-ios-more:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate-outline:before,.ion-ios-navigate:before,.ion-ios-nutrition-outline:before,.ion-ios-nutrition:before,.ion-ios-paper-outline:before,.ion-ios-paper:before,.ion-ios-paperplane-outline:before,.ion-ios-paperplane:before,.ion-ios-partlysunny-outline:before,.ion-ios-partlysunny:before,.ion-ios-pause-outline:before,.ion-ios-pause:before,.ion-ios-paw-outline:before,.ion-ios-paw:before,.ion-ios-people-outline:before,.ion-ios-people:before,.ion-ios-person-outline:before,.ion-ios-person:before,.ion-ios-personadd-outline:before,.ion-ios-personadd:before,.ion-ios-photos-outline:before,.ion-ios-photos:before,.ion-ios-pie-outline:before,.ion-ios-pie:before,.ion-ios-pint-outline:before,.ion-ios-pint:before,.ion-ios-play-outline:before,.ion-ios-play:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-plus:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetags-outline:before,.ion-ios-pricetags:before,.ion-ios-printer-outline:before,.ion-ios-printer:before,.ion-ios-pulse-strong:before,.ion-ios-pulse:before,.ion-ios-rainy-outline:before,.ion-ios-rainy:before,.ion-ios-recording-outline:before,.ion-ios-recording:before,.ion-ios-redo-outline:before,.ion-ios-redo:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-refresh:before,.ion-ios-reload:before,.ion-ios-reverse-camera-outline:before,.ion-ios-reverse-camera:before,.ion-ios-rewind-outline:before,.ion-ios-rewind:before,.ion-ios-rose-outline:before,.ion-ios-rose:before,.ion-ios-search-strong:before,.ion-ios-search:before,.ion-ios-settings-strong:before,.ion-ios-settings:before,.ion-ios-shuffle-strong:before,.ion-ios-shuffle:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipbackward:before,.ion-ios-skipforward-outline:before,.ion-ios-skipforward:before,.ion-ios-snowy:before,.ion-ios-speedometer-outline:before,.ion-ios-speedometer:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-star:before,.ion-ios-stopwatch-outline:before,.ion-ios-stopwatch:before,.ion-ios-sunny-outline:before,.ion-ios-sunny:before,.ion-ios-telephone-outline:before,.ion-ios-telephone:before,.ion-ios-tennisball-outline:before,.ion-ios-tennisball:before,.ion-ios-thunderstorm-outline:before,.ion-ios-thunderstorm:before,.ion-ios-time-outline:before,.ion-ios-time:before,.ion-ios-timer-outline:before,.ion-ios-timer:before,.ion-ios-toggle-outline:before,.ion-ios-toggle:before,.ion-ios-trash-outline:before,.ion-ios-trash:before,.ion-ios-undo-outline:before,.ion-ios-undo:before,.ion-ios-unlocked-outline:before,.ion-ios-unlocked:before,.ion-ios-upload-outline:before,.ion-ios-upload:before,.ion-ios-videocam-outline:before,.ion-ios-videocam:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass-outline:before,.ion-ios-wineglass:before,.ion-ios-world-outline:before,.ion-ios-world:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-minus:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon-round:before,.ion-navicon:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person-add:before,.ion-person-stalker:before,.ion-person:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-plus:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply-all:before,.ion-reply:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad-outline:before,.ion-sad:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android-outline:before,.ion-social-android:before,.ion-social-angular-outline:before,.ion-social-angular:before,.ion-social-apple-outline:before,.ion-social-apple:before,.ion-social-bitcoin-outline:before,.ion-social-bitcoin:before,.ion-social-buffer-outline:before,.ion-social-buffer:before,.ion-social-chrome-outline:before,.ion-social-chrome:before,.ion-social-codepen-outline:before,.ion-social-codepen:before,.ion-social-css3-outline:before,.ion-social-css3:before,.ion-social-designernews-outline:before,.ion-social-designernews:before,.ion-social-dribbble-outline:before,.ion-social-dribbble:before,.ion-social-dropbox-outline:before,.ion-social-dropbox:before,.ion-social-euro-outline:before,.ion-social-euro:before,.ion-social-facebook-outline:before,.ion-social-facebook:before,.ion-social-foursquare-outline:before,.ion-social-foursquare:before,.ion-social-freebsd-devil:before,.ion-social-github-outline:before,.ion-social-github:before,.ion-social-google-outline:before,.ion-social-google:before,.ion-social-googleplus-outline:before,.ion-social-googleplus:before,.ion-social-hackernews-outline:before,.ion-social-hackernews:before,.ion-social-html5-outline:before,.ion-social-html5:before,.ion-social-instagram-outline:before,.ion-social-instagram:before,.ion-social-javascript-outline:before,.ion-social-javascript:before,.ion-social-linkedin-outline:before,.ion-social-linkedin:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest-outline:before,.ion-social-pinterest:before,.ion-social-python:before,.ion-social-reddit-outline:before,.ion-social-reddit:before,.ion-social-rss-outline:before,.ion-social-rss:before,.ion-social-sass:before,.ion-social-skype-outline:before,.ion-social-skype:before,.ion-social-snapchat-outline:before,.ion-social-snapchat:before,.ion-social-tumblr-outline:before,.ion-social-tumblr:before,.ion-social-tux:before,.ion-social-twitch-outline:before,.ion-social-twitch:before,.ion-social-twitter-outline:before,.ion-social-twitter:before,.ion-social-usd-outline:before,.ion-social-usd:before,.ion-social-vimeo-outline:before,.ion-social-vimeo:before,.ion-social-whatsapp-outline:before,.ion-social-whatsapp:before,.ion-social-windows-outline:before,.ion-social-windows:before,.ion-social-wordpress-outline:before,.ion-social-wordpress:before,.ion-social-yahoo-outline:before,.ion-social-yahoo:before,.ion-social-yen-outline:before,.ion-social-yen:before,.ion-social-youtube-outline:before,.ion-social-youtube:before,.ion-soup-can-outline:before,.ion-soup-can:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle-filled:before,.ion-toggle:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt-outline:before,.ion-tshirt:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before,.ionicons{display:inline-block;font-family:Ionicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ion-alert:before{content:""}.ion-alert-circled:before{content:""}.ion-android-add:before{content:""}.ion-android-add-circle:before{content:""}.ion-android-alarm-clock:before{content:""}.ion-android-alert:before{content:""}.ion-android-apps:before{content:""}.ion-android-archive:before{content:""}.ion-android-arrow-back:before{content:""}.ion-android-arrow-down:before{content:""}.ion-android-arrow-dropdown:before{content:""}.ion-android-arrow-dropdown-circle:before{content:""}.ion-android-arrow-dropleft:before{content:""}.ion-android-arrow-dropleft-circle:before{content:""}.ion-android-arrow-dropright:before{content:""}.ion-android-arrow-dropright-circle:before{content:""}.ion-android-arrow-dropup:before{content:""}.ion-android-arrow-dropup-circle:before{content:""}.ion-android-arrow-forward:before{content:""}.ion-android-arrow-up:before{content:""}.ion-android-attach:before{content:""}.ion-android-bar:before{content:""}.ion-android-bicycle:before{content:""}.ion-android-boat:before{content:""}.ion-android-bookmark:before{content:""}.ion-android-bulb:before{content:""}.ion-android-bus:before{content:""}.ion-android-calendar:before{content:""}.ion-android-call:before{content:""}.ion-android-camera:before{content:""}.ion-android-cancel:before{content:""}.ion-android-car:before{content:""}.ion-android-cart:before{content:""}.ion-android-chat:before{content:""}.ion-android-checkbox:before{content:""}.ion-android-checkbox-blank:before{content:""}.ion-android-checkbox-outline:before{content:""}.ion-android-checkbox-outline-blank:before{content:""}.ion-android-checkmark-circle:before{content:""}.ion-android-clipboard:before{content:""}.ion-android-close:before{content:""}.ion-android-cloud:before{content:""}.ion-android-cloud-circle:before{content:""}.ion-android-cloud-done:before{content:""}.ion-android-cloud-outline:before{content:""}.ion-android-color-palette:before{content:""}.ion-android-compass:before{content:""}.ion-android-contact:before{content:""}.ion-android-contacts:before{content:""}.ion-android-contract:before{content:""}.ion-android-create:before{content:""}.ion-android-delete:before{content:""}.ion-android-desktop:before{content:""}.ion-android-document:before{content:""}.ion-android-done:before{content:""}.ion-android-done-all:before{content:""}.ion-android-download:before{content:""}.ion-android-drafts:before{content:""}.ion-android-exit:before{content:""}.ion-android-expand:before{content:""}.ion-android-favorite:before{content:""}.ion-android-favorite-outline:before{content:""}.ion-android-film:before{content:""}.ion-android-folder:before{content:""}.ion-android-folder-open:before{content:""}.ion-android-funnel:before{content:""}.ion-android-globe:before{content:""}.ion-android-hand:before{content:""}.ion-android-hangout:before{content:""}.ion-android-happy:before{content:""}.ion-android-home:before{content:""}.ion-android-image:before{content:""}.ion-android-laptop:before{content:""}.ion-android-list:before{content:""}.ion-android-locate:before{content:""}.ion-android-lock:before{content:""}.ion-android-mail:before{content:""}.ion-android-map:before{content:""}.ion-android-menu:before{content:""}.ion-android-microphone:before{content:""}.ion-android-microphone-off:before{content:""}.ion-android-more-horizontal:before{content:""}.ion-android-more-vertical:before{content:""}.ion-android-navigate:before{content:""}.ion-android-notifications:before{content:""}.ion-android-notifications-none:before{content:""}.ion-android-notifications-off:before{content:""}.ion-android-open:before{content:""}.ion-android-options:before{content:""}.ion-android-people:before{content:""}.ion-android-person:before{content:""}.ion-android-person-add:before{content:""}.ion-android-phone-landscape:before{content:""}.ion-android-phone-portrait:before{content:""}.ion-android-pin:before{content:""}.ion-android-plane:before{content:""}.ion-android-playstore:before{content:""}.ion-android-print:before{content:""}.ion-android-radio-button-off:before{content:""}.ion-android-radio-button-on:before{content:""}.ion-android-refresh:before{content:""}.ion-android-remove:before{content:""}.ion-android-remove-circle:before{content:""}.ion-android-restaurant:before{content:""}.ion-android-sad:before{content:""}.ion-android-search:before{content:""}.ion-android-send:before{content:""}.ion-android-settings:before{content:""}.ion-android-share:before{content:""}.ion-android-share-alt:before{content:""}.ion-android-star:before{content:""}.ion-android-star-half:before{content:""}.ion-android-star-outline:before{content:""}.ion-android-stopwatch:before{content:""}.ion-android-subway:before{content:""}.ion-android-sunny:before{content:""}.ion-android-sync:before{content:""}.ion-android-textsms:before{content:""}.ion-android-time:before{content:""}.ion-android-train:before{content:""}.ion-android-unlock:before{content:""}.ion-android-upload:before{content:""}.ion-android-volume-down:before{content:""}.ion-android-volume-mute:before{content:""}.ion-android-volume-off:before{content:""}.ion-android-volume-up:before{content:""}.ion-android-walk:before{content:""}.ion-android-warning:before{content:""}.ion-android-watch:before{content:""}.ion-android-wifi:before{content:""}.ion-aperture:before{content:""}.ion-archive:before{content:""}.ion-arrow-down-a:before{content:""}.ion-arrow-down-b:before{content:""}.ion-arrow-down-c:before{content:""}.ion-arrow-expand:before{content:""}.ion-arrow-graph-down-left:before{content:""}.ion-arrow-graph-down-right:before{content:""}.ion-arrow-graph-up-left:before{content:""}.ion-arrow-graph-up-right:before{content:""}.ion-arrow-left-a:before{content:""}.ion-arrow-left-b:before{content:""}.ion-arrow-left-c:before{content:""}.ion-arrow-move:before{content:""}.ion-arrow-resize:before{content:""}.ion-arrow-return-left:before{content:""}.ion-arrow-return-right:before{content:""}.ion-arrow-right-a:before{content:""}.ion-arrow-right-b:before{content:""}.ion-arrow-right-c:before{content:""}.ion-arrow-shrink:before{content:""}.ion-arrow-swap:before{content:""}.ion-arrow-up-a:before{content:""}.ion-arrow-up-b:before{content:""}.ion-arrow-up-c:before{content:""}.ion-asterisk:before{content:""}.ion-at:before{content:""}.ion-backspace:before{content:""}.ion-backspace-outline:before{content:""}.ion-bag:before{content:""}.ion-battery-charging:before{content:""}.ion-battery-empty:before{content:""}.ion-battery-full:before{content:""}.ion-battery-half:before{content:""}.ion-battery-low:before{content:""}.ion-beaker:before{content:""}.ion-beer:before{content:""}.ion-bluetooth:before{content:""}.ion-bonfire:before{content:""}.ion-bookmark:before{content:""}.ion-bowtie:before{content:""}.ion-briefcase:before{content:""}.ion-bug:before{content:""}.ion-calculator:before{content:""}.ion-calendar:before{content:""}.ion-camera:before{content:""}.ion-card:before{content:""}.ion-cash:before{content:""}.ion-chatbox:before{content:""}.ion-chatbox-working:before{content:""}.ion-chatboxes:before{content:""}.ion-chatbubble:before{content:""}.ion-chatbubble-working:before{content:""}.ion-chatbubbles:before{content:""}.ion-checkmark:before{content:""}.ion-checkmark-circled:before{content:""}.ion-checkmark-round:before{content:""}.ion-chevron-down:before{content:""}.ion-chevron-left:before{content:""}.ion-chevron-right:before{content:""}.ion-chevron-up:before{content:""}.ion-clipboard:before{content:""}.ion-clock:before{content:""}.ion-close:before{content:""}.ion-close-circled:before{content:""}.ion-close-round:before{content:""}.ion-closed-captioning:before{content:""}.ion-cloud:before{content:""}.ion-code:before{content:""}.ion-code-download:before{content:""}.ion-code-working:before{content:""}.ion-coffee:before{content:""}.ion-compass:before{content:""}.ion-compose:before{content:""}.ion-connection-bars:before{content:""}.ion-contrast:before{content:""}.ion-crop:before{content:""}.ion-cube:before{content:""}.ion-disc:before{content:""}.ion-document:before{content:""}.ion-document-text:before{content:""}.ion-drag:before{content:""}.ion-earth:before{content:""}.ion-easel:before{content:""}.ion-edit:before{content:""}.ion-egg:before{content:""}.ion-eject:before{content:""}.ion-email:before{content:""}.ion-email-unread:before{content:""}.ion-erlenmeyer-flask:before{content:""}.ion-erlenmeyer-flask-bubbles:before{content:""}.ion-eye:before{content:""}.ion-eye-disabled:before{content:""}.ion-female:before{content:""}.ion-filing:before{content:""}.ion-film-marker:before{content:""}.ion-fireball:before{content:""}.ion-flag:before{content:""}.ion-flame:before{content:""}.ion-flash:before{content:""}.ion-flash-off:before{content:""}.ion-folder:before{content:""}.ion-fork:before{content:""}.ion-fork-repo:before{content:""}.ion-forward:before{content:""}.ion-funnel:before{content:""}.ion-gear-a:before{content:""}.ion-gear-b:before{content:""}.ion-grid:before{content:""}.ion-hammer:before{content:""}.ion-happy:before{content:""}.ion-happy-outline:before{content:""}.ion-headphone:before{content:""}.ion-heart:before{content:""}.ion-heart-broken:before{content:""}.ion-help:before{content:""}.ion-help-buoy:before{content:""}.ion-help-circled:before{content:""}.ion-home:before{content:""}.ion-icecream:before{content:""}.ion-image:before{content:""}.ion-images:before{content:""}.ion-information:before{content:""}.ion-information-circled:before{content:""}.ion-ionic:before{content:""}.ion-ios-alarm:before{content:""}.ion-ios-alarm-outline:before{content:""}.ion-ios-albums:before{content:""}.ion-ios-albums-outline:before{content:""}.ion-ios-americanfootball:before{content:""}.ion-ios-americanfootball-outline:before{content:""}.ion-ios-analytics:before{content:""}.ion-ios-analytics-outline:before{content:""}.ion-ios-arrow-back:before{content:""}.ion-ios-arrow-down:before{content:""}.ion-ios-arrow-forward:before{content:""}.ion-ios-arrow-left:before{content:""}.ion-ios-arrow-right:before{content:""}.ion-ios-arrow-thin-down:before{content:""}.ion-ios-arrow-thin-left:before{content:""}.ion-ios-arrow-thin-right:before{content:""}.ion-ios-arrow-thin-up:before{content:""}.ion-ios-arrow-up:before{content:""}.ion-ios-at:before{content:""}.ion-ios-at-outline:before{content:""}.ion-ios-barcode:before{content:""}.ion-ios-barcode-outline:before{content:""}.ion-ios-baseball:before{content:""}.ion-ios-baseball-outline:before{content:""}.ion-ios-basketball:before{content:""}.ion-ios-basketball-outline:before{content:""}.ion-ios-bell:before{content:""}.ion-ios-bell-outline:before{content:""}.ion-ios-body:before{content:""}.ion-ios-body-outline:before{content:""}.ion-ios-bolt:before{content:""}.ion-ios-bolt-outline:before{content:""}.ion-ios-book:before{content:""}.ion-ios-book-outline:before{content:""}.ion-ios-bookmarks:before{content:""}.ion-ios-bookmarks-outline:before{content:""}.ion-ios-box:before{content:""}.ion-ios-box-outline:before{content:""}.ion-ios-briefcase:before{content:""}.ion-ios-briefcase-outline:before{content:""}.ion-ios-browsers:before{content:""}.ion-ios-browsers-outline:before{content:""}.ion-ios-calculator:before{content:""}.ion-ios-calculator-outline:before{content:""}.ion-ios-calendar:before{content:""}.ion-ios-calendar-outline:before{content:""}.ion-ios-camera:before{content:""}.ion-ios-camera-outline:before{content:""}.ion-ios-cart:before{content:""}.ion-ios-cart-outline:before{content:""}.ion-ios-chatboxes:before{content:""}.ion-ios-chatboxes-outline:before{content:""}.ion-ios-chatbubble:before{content:""}.ion-ios-chatbubble-outline:before{content:""}.ion-ios-checkmark:before{content:""}.ion-ios-checkmark-empty:before{content:""}.ion-ios-checkmark-outline:before{content:""}.ion-ios-circle-filled:before{content:""}.ion-ios-circle-outline:before{content:""}.ion-ios-clock:before{content:""}.ion-ios-clock-outline:before{content:""}.ion-ios-close:before{content:""}.ion-ios-close-empty:before{content:""}.ion-ios-close-outline:before{content:""}.ion-ios-cloud:before{content:""}.ion-ios-cloud-download:before{content:""}.ion-ios-cloud-download-outline:before{content:""}.ion-ios-cloud-outline:before{content:""}.ion-ios-cloud-upload:before{content:""}.ion-ios-cloud-upload-outline:before{content:""}.ion-ios-cloudy:before{content:""}.ion-ios-cloudy-night:before{content:""}.ion-ios-cloudy-night-outline:before{content:""}.ion-ios-cloudy-outline:before{content:""}.ion-ios-cog:before{content:""}.ion-ios-cog-outline:before{content:""}.ion-ios-color-filter:before{content:""}.ion-ios-color-filter-outline:before{content:""}.ion-ios-color-wand:before{content:""}.ion-ios-color-wand-outline:before{content:""}.ion-ios-compose:before{content:""}.ion-ios-compose-outline:before{content:""}.ion-ios-contact:before{content:""}.ion-ios-contact-outline:before{content:""}.ion-ios-copy:before{content:""}.ion-ios-copy-outline:before{content:""}.ion-ios-crop:before{content:""}.ion-ios-crop-strong:before{content:""}.ion-ios-download:before{content:""}.ion-ios-download-outline:before{content:""}.ion-ios-drag:before{content:""}.ion-ios-email:before{content:""}.ion-ios-email-outline:before{content:""}.ion-ios-eye:before{content:""}.ion-ios-eye-outline:before{content:""}.ion-ios-fastforward:before{content:""}.ion-ios-fastforward-outline:before{content:""}.ion-ios-filing:before{content:""}.ion-ios-filing-outline:before{content:""}.ion-ios-film:before{content:""}.ion-ios-film-outline:before{content:""}.ion-ios-flag:before{content:""}.ion-ios-flag-outline:before{content:""}.ion-ios-flame:before{content:""}.ion-ios-flame-outline:before{content:""}.ion-ios-flask:before{content:""}.ion-ios-flask-outline:before{content:""}.ion-ios-flower:before{content:""}.ion-ios-flower-outline:before{content:""}.ion-ios-folder:before{content:""}.ion-ios-folder-outline:before{content:""}.ion-ios-football:before{content:""}.ion-ios-football-outline:before{content:""}.ion-ios-game-controller-a:before{content:""}.ion-ios-game-controller-a-outline:before{content:""}.ion-ios-game-controller-b:before{content:""}.ion-ios-game-controller-b-outline:before{content:""}.ion-ios-gear:before{content:""}.ion-ios-gear-outline:before{content:""}.ion-ios-glasses:before{content:""}.ion-ios-glasses-outline:before{content:""}.ion-ios-grid-view:before{content:""}.ion-ios-grid-view-outline:before{content:""}.ion-ios-heart:before{content:""}.ion-ios-heart-outline:before{content:""}.ion-ios-help:before{content:""}.ion-ios-help-empty:before{content:""}.ion-ios-help-outline:before{content:""}.ion-ios-home:before{content:""}.ion-ios-home-outline:before{content:""}.ion-ios-infinite:before{content:""}.ion-ios-infinite-outline:before{content:""}.ion-ios-information:before{content:""}.ion-ios-information-empty:before{content:""}.ion-ios-information-outline:before{content:""}.ion-ios-ionic-outline:before{content:""}.ion-ios-keypad:before{content:""}.ion-ios-keypad-outline:before{content:""}.ion-ios-lightbulb:before{content:""}.ion-ios-lightbulb-outline:before{content:""}.ion-ios-list:before{content:""}.ion-ios-list-outline:before{content:""}.ion-ios-location:before{content:""}.ion-ios-location-outline:before{content:""}.ion-ios-locked:before{content:""}.ion-ios-locked-outline:before{content:""}.ion-ios-loop:before{content:""}.ion-ios-loop-strong:before{content:""}.ion-ios-medical:before{content:""}.ion-ios-medical-outline:before{content:""}.ion-ios-medkit:before{content:""}.ion-ios-medkit-outline:before{content:""}.ion-ios-mic:before{content:""}.ion-ios-mic-off:before{content:""}.ion-ios-mic-outline:before{content:""}.ion-ios-minus:before{content:""}.ion-ios-minus-empty:before{content:""}.ion-ios-minus-outline:before{content:""}.ion-ios-monitor:before{content:""}.ion-ios-monitor-outline:before{content:""}.ion-ios-moon:before{content:""}.ion-ios-moon-outline:before{content:""}.ion-ios-more:before{content:""}.ion-ios-more-outline:before{content:""}.ion-ios-musical-note:before{content:""}.ion-ios-musical-notes:before{content:""}.ion-ios-navigate:before{content:""}.ion-ios-navigate-outline:before{content:""}.ion-ios-nutrition:before{content:""}.ion-ios-nutrition-outline:before{content:""}.ion-ios-paper:before{content:""}.ion-ios-paper-outline:before{content:""}.ion-ios-paperplane:before{content:""}.ion-ios-paperplane-outline:before{content:""}.ion-ios-partlysunny:before{content:""}.ion-ios-partlysunny-outline:before{content:""}.ion-ios-pause:before{content:""}.ion-ios-pause-outline:before{content:""}.ion-ios-paw:before{content:""}.ion-ios-paw-outline:before{content:""}.ion-ios-people:before{content:""}.ion-ios-people-outline:before{content:""}.ion-ios-person:before{content:""}.ion-ios-person-outline:before{content:""}.ion-ios-personadd:before{content:""}.ion-ios-personadd-outline:before{content:""}.ion-ios-photos:before{content:""}.ion-ios-photos-outline:before{content:""}.ion-ios-pie:before{content:""}.ion-ios-pie-outline:before{content:""}.ion-ios-pint:before{content:""}.ion-ios-pint-outline:before{content:""}.ion-ios-play:before{content:""}.ion-ios-play-outline:before{content:""}.ion-ios-plus:before{content:""}.ion-ios-plus-empty:before{content:""}.ion-ios-plus-outline:before{content:""}.ion-ios-pricetag:before{content:""}.ion-ios-pricetag-outline:before{content:""}.ion-ios-pricetags:before{content:""}.ion-ios-pricetags-outline:before{content:""}.ion-ios-printer:before{content:""}.ion-ios-printer-outline:before{content:""}.ion-ios-pulse:before{content:""}.ion-ios-pulse-strong:before{content:""}.ion-ios-rainy:before{content:""}.ion-ios-rainy-outline:before{content:""}.ion-ios-recording:before{content:""}.ion-ios-recording-outline:before{content:""}.ion-ios-redo:before{content:""}.ion-ios-redo-outline:before{content:""}.ion-ios-refresh:before{content:""}.ion-ios-refresh-empty:before{content:""}.ion-ios-refresh-outline:before{content:""}.ion-ios-reload:before{content:""}.ion-ios-reverse-camera:before{content:""}.ion-ios-reverse-camera-outline:before{content:""}.ion-ios-rewind:before{content:""}.ion-ios-rewind-outline:before{content:""}.ion-ios-rose:before{content:""}.ion-ios-rose-outline:before{content:""}.ion-ios-search:before{content:""}.ion-ios-search-strong:before{content:""}.ion-ios-settings:before{content:""}.ion-ios-settings-strong:before{content:""}.ion-ios-shuffle:before{content:""}.ion-ios-shuffle-strong:before{content:""}.ion-ios-skipbackward:before{content:""}.ion-ios-skipbackward-outline:before{content:""}.ion-ios-skipforward:before{content:""}.ion-ios-skipforward-outline:before{content:""}.ion-ios-snowy:before{content:""}.ion-ios-speedometer:before{content:""}.ion-ios-speedometer-outline:before{content:""}.ion-ios-star:before{content:""}.ion-ios-star-half:before{content:""}.ion-ios-star-outline:before{content:""}.ion-ios-stopwatch:before{content:""}.ion-ios-stopwatch-outline:before{content:""}.ion-ios-sunny:before{content:""}.ion-ios-sunny-outline:before{content:""}.ion-ios-telephone:before{content:""}.ion-ios-telephone-outline:before{content:""}.ion-ios-tennisball:before{content:""}.ion-ios-tennisball-outline:before{content:""}.ion-ios-thunderstorm:before{content:""}.ion-ios-thunderstorm-outline:before{content:""}.ion-ios-time:before{content:""}.ion-ios-time-outline:before{content:""}.ion-ios-timer:before{content:""}.ion-ios-timer-outline:before{content:""}.ion-ios-toggle:before{content:""}.ion-ios-toggle-outline:before{content:""}.ion-ios-trash:before{content:""}.ion-ios-trash-outline:before{content:""}.ion-ios-undo:before{content:""}.ion-ios-undo-outline:before{content:""}.ion-ios-unlocked:before{content:""}.ion-ios-unlocked-outline:before{content:""}.ion-ios-upload:before{content:""}.ion-ios-upload-outline:before{content:""}.ion-ios-videocam:before{content:""}.ion-ios-videocam-outline:before{content:""}.ion-ios-volume-high:before{content:""}.ion-ios-volume-low:before{content:""}.ion-ios-wineglass:before{content:""}.ion-ios-wineglass-outline:before{content:""}.ion-ios-world:before{content:""}.ion-ios-world-outline:before{content:""}.ion-ipad:before{content:""}.ion-iphone:before{content:""}.ion-ipod:before{content:""}.ion-jet:before{content:""}.ion-key:before{content:""}.ion-knife:before{content:""}.ion-laptop:before{content:""}.ion-leaf:before{content:""}.ion-levels:before{content:""}.ion-lightbulb:before{content:""}.ion-link:before{content:""}.ion-load-a:before{content:""}.ion-load-b:before{content:""}.ion-load-c:before{content:""}.ion-load-d:before{content:""}.ion-location:before{content:""}.ion-lock-combination:before{content:""}.ion-locked:before{content:""}.ion-log-in:before{content:""}.ion-log-out:before{content:""}.ion-loop:before{content:""}.ion-magnet:before{content:""}.ion-male:before{content:""}.ion-man:before{content:""}.ion-map:before{content:""}.ion-medkit:before{content:""}.ion-merge:before{content:""}.ion-mic-a:before{content:""}.ion-mic-b:before{content:""}.ion-mic-c:before{content:""}.ion-minus:before{content:""}.ion-minus-circled:before{content:""}.ion-minus-round:before{content:""}.ion-model-s:before{content:""}.ion-monitor:before{content:""}.ion-more:before{content:""}.ion-mouse:before{content:""}.ion-music-note:before{content:""}.ion-navicon:before{content:""}.ion-navicon-round:before{content:""}.ion-navigate:before{content:""}.ion-network:before{content:""}.ion-no-smoking:before{content:""}.ion-nuclear:before{content:""}.ion-outlet:before{content:""}.ion-paintbrush:before{content:""}.ion-paintbucket:before{content:""}.ion-paper-airplane:before{content:""}.ion-paperclip:before{content:""}.ion-pause:before{content:""}.ion-person:before{content:""}.ion-person-add:before{content:""}.ion-person-stalker:before{content:""}.ion-pie-graph:before{content:""}.ion-pin:before{content:""}.ion-pinpoint:before{content:""}.ion-pizza:before{content:""}.ion-plane:before{content:""}.ion-planet:before{content:""}.ion-play:before{content:""}.ion-playstation:before{content:""}.ion-plus:before{content:""}.ion-plus-circled:before{content:""}.ion-plus-round:before{content:""}.ion-podium:before{content:""}.ion-pound:before{content:""}.ion-power:before{content:""}.ion-pricetag:before{content:""}.ion-pricetags:before{content:""}.ion-printer:before{content:""}.ion-pull-request:before{content:""}.ion-qr-scanner:before{content:""}.ion-quote:before{content:""}.ion-radio-waves:before{content:""}.ion-record:before{content:""}.ion-refresh:before{content:""}.ion-reply:before{content:""}.ion-reply-all:before{content:""}.ion-ribbon-a:before{content:""}.ion-ribbon-b:before{content:""}.ion-sad:before{content:""}.ion-sad-outline:before{content:""}.ion-scissors:before{content:""}.ion-search:before{content:""}.ion-settings:before{content:""}.ion-share:before{content:""}.ion-shuffle:before{content:""}.ion-skip-backward:before{content:""}.ion-skip-forward:before{content:""}.ion-social-android:before{content:""}.ion-social-android-outline:before{content:""}.ion-social-angular:before{content:""}.ion-social-angular-outline:before{content:""}.ion-social-apple:before{content:""}.ion-social-apple-outline:before{content:""}.ion-social-bitcoin:before{content:""}.ion-social-bitcoin-outline:before{content:""}.ion-social-buffer:before{content:""}.ion-social-buffer-outline:before{content:""}.ion-social-chrome:before{content:""}.ion-social-chrome-outline:before{content:""}.ion-social-codepen:before{content:""}.ion-social-codepen-outline:before{content:""}.ion-social-css3:before{content:""}.ion-social-css3-outline:before{content:""}.ion-social-designernews:before{content:""}.ion-social-designernews-outline:before{content:""}.ion-social-dribbble:before{content:""}.ion-social-dribbble-outline:before{content:""}.ion-social-dropbox:before{content:""}.ion-social-dropbox-outline:before{content:""}.ion-social-euro:before{content:""}.ion-social-euro-outline:before{content:""}.ion-social-facebook:before{content:""}.ion-social-facebook-outline:before{content:""}.ion-social-foursquare:before{content:""}.ion-social-foursquare-outline:before{content:""}.ion-social-freebsd-devil:before{content:""}.ion-social-github:before{content:""}.ion-social-github-outline:before{content:""}.ion-social-google:before{content:""}.ion-social-google-outline:before{content:""}.ion-social-googleplus:before{content:""}.ion-social-googleplus-outline:before{content:""}.ion-social-hackernews:before{content:""}.ion-social-hackernews-outline:before{content:""}.ion-social-html5:before{content:""}.ion-social-html5-outline:before{content:""}.ion-social-instagram:before{content:""}.ion-social-instagram-outline:before{content:""}.ion-social-javascript:before{content:""}.ion-social-javascript-outline:before{content:""}.ion-social-linkedin:before{content:""}.ion-social-linkedin-outline:before{content:""}.ion-social-markdown:before{content:""}.ion-social-nodejs:before{content:""}.ion-social-octocat:before{content:""}.ion-social-pinterest:before{content:""}.ion-social-pinterest-outline:before{content:""}.ion-social-python:before{content:""}.ion-social-reddit:before{content:""}.ion-social-reddit-outline:before{content:""}.ion-social-rss:before{content:""}.ion-social-rss-outline:before{content:""}.ion-social-sass:before{content:""}.ion-social-skype:before{content:""}.ion-social-skype-outline:before{content:""}.ion-social-snapchat:before{content:""}.ion-social-snapchat-outline:before{content:""}.ion-social-tumblr:before{content:""}.ion-social-tumblr-outline:before{content:""}.ion-social-tux:before{content:""}.ion-social-twitch:before{content:""}.ion-social-twitch-outline:before{content:""}.ion-social-twitter:before{content:""}.ion-social-twitter-outline:before{content:""}.ion-social-usd:before{content:""}.ion-social-usd-outline:before{content:""}.ion-social-vimeo:before{content:""}.ion-social-vimeo-outline:before{content:""}.ion-social-whatsapp:before{content:""}.ion-social-whatsapp-outline:before{content:""}.ion-social-windows:before{content:""}.ion-social-windows-outline:before{content:""}.ion-social-wordpress:before{content:""}.ion-social-wordpress-outline:before{content:""}.ion-social-yahoo:before{content:""}.ion-social-yahoo-outline:before{content:""}.ion-social-yen:before{content:""}.ion-social-yen-outline:before{content:""}.ion-social-youtube:before{content:""}.ion-social-youtube-outline:before{content:""}.ion-soup-can:before{content:""}.ion-soup-can-outline:before{content:""}.ion-speakerphone:before{content:""}.ion-speedometer:before{content:""}.ion-spoon:before{content:""}.ion-star:before{content:""}.ion-stats-bars:before{content:""}.ion-steam:before{content:""}.ion-stop:before{content:""}.ion-thermometer:before{content:""}.ion-thumbsdown:before{content:""}.ion-thumbsup:before{content:""}.ion-toggle:before{content:""}.ion-toggle-filled:before{content:""}.ion-transgender:before{content:""}.ion-trash-a:before{content:""}.ion-trash-b:before{content:""}.ion-trophy:before{content:""}.ion-tshirt:before{content:""}.ion-tshirt-outline:before{content:""}.ion-umbrella:before{content:""}.ion-university:before{content:""}.ion-unlocked:before{content:""}.ion-upload:before{content:""}.ion-usb:before{content:""}.ion-videocamera:before{content:""}.ion-volume-high:before{content:""}.ion-volume-low:before{content:""}.ion-volume-medium:before{content:""}.ion-volume-mute:before{content:""}.ion-wand:before{content:""}.ion-waterdrop:before{content:""}.ion-wifi:before{content:""}.ion-wineglass:before{content:""}.ion-woman:before{content:""}.ion-wrench:before{content:""}.ion-xbox:before{content:""}a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0;border:0;vertical-align:baseline;font:inherit;font-size:100%}ol,ul{list-style:none}blockquote,q{quotes:none}audio:not([controls]){display:none;height:0}[hidden],template{display:none}script{display:none!important}html{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}:focus,a,a:active,a:focus,a:hover,button,button:focus{outline:0}a{-webkit-user-drag:none;-webkit-tap-highlight-color:transparent;-webkit-tap-highlight-color:transparent}a[href]:hover{cursor:pointer}b,strong{font-weight:700}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}code,kbd,pre,samp{font-size:1em;font-family:monospace,serif}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}sub,sup{position:relative;vertical-align:baseline;font-size:75%;line-height:0}sup{top:-.5em}sub{bottom:-.25em}fieldset{margin:0 2px;padding:.35em .625em .75em;border:1px solid silver}button,input,select,textarea{margin:0;outline-offset:0;outline-style:none;outline-width:0;-webkit-font-smoothing:inherit;background-image:none}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto}img{-webkit-user-drag:none}table{border-spacing:0;border-collapse:collapse}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{overflow:hidden;-ms-touch-action:pan-y;touch-action:pan-y}.ionic-body,body{-webkit-touch-callout:none;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;-webkit-tap-highlight-color:transparent;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0;padding:0;color:#000;word-wrap:break-word;font-size:14px;font-family:-apple-system;font-family:"-apple-system","Helvetica Neue",Roboto,"Segoe UI",sans-serif;line-height:20px;text-rendering:optimizeLegibility;-webkit-backface-visibility:hidden;-webkit-user-drag:none;-ms-content-zooming:none}body.grade-b,body.grade-c{text-rendering:auto}.content{position:relative}.scroll-content{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;margin-top:-1px;padding-top:1px;margin-bottom:-1px;width:auto;height:auto}.menu .scroll-content.scroll-content-false{z-index:11}.scroll-view{position:relative;display:block;overflow:hidden;margin-top:-1px}.scroll-view.overflow-scroll{position:relative}.scroll-view.scroll-x{overflow-x:scroll;overflow-y:hidden}.scroll-view.scroll-y{overflow-x:hidden;overflow-y:scroll}.scroll-view.scroll-xy{overflow-x:scroll;overflow-y:scroll}.scroll{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none;-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;-webkit-transform-origin:left top;transform-origin:left top}@-ms-viewport{width:device-width}.scroll-bar{position:absolute;z-index:9999}.ng-animate .scroll-bar{visibility:hidden}.scroll-bar-h{right:2px;bottom:3px;left:2px;height:3px}.scroll-bar-h .scroll-bar-indicator{height:100%}.scroll-bar-v{top:2px;right:3px;bottom:2px;width:3px}.scroll-bar-v .scroll-bar-indicator{width:100%}.scroll-bar-indicator{position:absolute;border-radius:4px;background:rgba(0,0,0,.3);opacity:1;-webkit-transition:opacity .3s linear;transition:opacity .3s linear}.scroll-bar-indicator.scroll-bar-fade-out{opacity:0}.platform-android .scroll-bar-indicator{border-radius:0}.grade-b .scroll-bar-indicator,.grade-c .scroll-bar-indicator{background:#aaa}.grade-b .scroll-bar-indicator.scroll-bar-fade-out,.grade-c .scroll-bar-indicator.scroll-bar-fade-out{-webkit-transition:none;transition:none}ion-infinite-scroll{height:60px;width:100%;display:block;display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-direction:normal;-webkit-box-orient:horizontal;-webkit-flex-direction:row;-moz-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;-moz-justify-content:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center}ion-infinite-scroll .icon{font-size:30px;color:#666}ion-infinite-scroll:not(.active) .icon:before,ion-infinite-scroll:not(.active) .spinner{display:none}.overflow-scroll{overflow-x:hidden;overflow-y:scroll;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;top:0;right:0;bottom:0;left:0;position:absolute}.overflow-scroll.pane{overflow-x:hidden;overflow-y:scroll}.overflow-scroll .scroll{position:static;height:100%;-webkit-transform:translate3d(0,0,0)}.has-header{top:44px}.no-header{top:0}.has-subheader{top:88px}.has-tabs-top{top:93px}.has-header.has-subheader.has-tabs-top{top:137px}.has-footer{bottom:44px}.has-subfooter{bottom:88px}.bar-footer.has-tabs,.has-tabs{bottom:49px}.bar-footer.has-tabs.pane,.has-tabs.pane{bottom:49px;height:auto}.bar-subfooter.has-tabs,.has-footer.has-tabs{bottom:93px}.pane{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-transition-duration:0;transition-duration:0;z-index:1}.view{z-index:1}.pane,.view{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background-color:#fff;overflow:hidden}.view-container{position:absolute;display:block;width:100%;height:100%}p{margin:0 0 10px}small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{color:#000;font-weight:500;font-family:"-apple-system","Helvetica Neue",Roboto,"Segoe UI",sans-serif;line-height:1.2}.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:400;line-height:1}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1:first-child,.h2:first-child,.h3:first-child,h1:first-child,h2:first-child,h3:first-child{margin-top:0}.h1+.h1,.h1+.h2,.h1+.h3,.h1+h1,.h1+h2,.h1+h3,.h2+.h1,.h2+.h2,.h2+.h3,.h2+h1,.h2+h2,.h2+h3,.h3+.h1,.h3+.h2,.h3+.h3,.h3+h1,.h3+h2,.h3+h3,h1+.h1,h1+.h2,h1+.h3,h1+h1,h1+h2,h1+h3,h2+.h1,h2+.h2,h2+.h3,h2+h1,h2+h2,h2+h3,h3+.h1,h3+.h2,h3+.h3,h3+h1,h3+h2,h3+h3{margin-top:10px}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}.h1 small,h1 small{font-size:24px}.h2 small,h2 small{font-size:18px}.h3 small,.h4 small,h3 small,h4 small{font-size:14px}dl{margin-bottom:20px}dd,dt{line-height:1.42857}dt{font-weight:700}blockquote{margin:0 0 20px;padding:10px 20px;border-left:5px solid gray}blockquote p{font-weight:300;font-size:17.5px;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.42857}blockquote small:before{content:'\2014 \00A0'}blockquote:after,blockquote:before,q:after,q:before{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:1.42857}a{color:#387ef5}a.subdued{padding-right:10px;color:#888;text-decoration:none}a.subdued:hover{text-decoration:none}a.subdued:last-child{padding-right:0}.action-sheet-backdrop{-webkit-transition:background-color 150ms ease-in-out;transition:background-color 150ms ease-in-out;position:fixed;top:0;left:0;z-index:11;width:100%;height:100%;background-color:transparent}.action-sheet-backdrop.active{background-color:rgba(0,0,0,.4)}.action-sheet-wrapper{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);-webkit-transition:all cubic-bezier(.36,.66,.04,1) 500ms;transition:all cubic-bezier(.36,.66,.04,1) 500ms;position:absolute;bottom:0;left:0;right:0;width:100%;max-width:500px;margin:auto}.action-sheet-up{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.action-sheet{margin-left:8px;margin-right:8px;width:auto;z-index:11;overflow:hidden}.action-sheet .button{display:block;padding:1px;width:100%;border-radius:0;border-color:#d1d3d6;background-color:transparent;color:#007aff;font-size:21px}.action-sheet .button:hover{color:#007aff}.action-sheet .button.destructive,.action-sheet .button.destructive:hover{color:#ff3b30}.action-sheet .button.activated,.action-sheet .button.active{box-shadow:none;border-color:#d1d3d6;color:#007aff;background:#e4e5e7}.action-sheet-has-icons .icon{position:absolute;left:16px}.action-sheet-title{padding:16px;color:#8f8f8f;text-align:center;font-size:13px}.action-sheet-group{margin-bottom:8px;border-radius:4px;background-color:#fff;overflow:hidden}.action-sheet-group .button{border-width:1px 0 0 0}.action-sheet-group .button:first-child:last-child{border-width:0}.action-sheet-options{background:#f1f2f3}.action-sheet-cancel .button{font-weight:500}.action-sheet-open,.action-sheet-open.modal-open .modal{pointer-events:none}.action-sheet-open .action-sheet-backdrop{pointer-events:auto}.platform-android .action-sheet-backdrop.active{background-color:rgba(0,0,0,.2)}.platform-android .action-sheet{margin:0}.platform-android .action-sheet .action-sheet-title,.platform-android .action-sheet .button{text-align:left;border-color:transparent;font-size:16px;color:inherit}.platform-android .action-sheet .action-sheet-title{font-size:14px;padding:16px;color:#666}.platform-android .action-sheet .button.activated,.platform-android .action-sheet .button.active{background:#e8e8e8}.platform-android .action-sheet-group{margin:0;border-radius:0;background-color:#fafafa}.platform-android .action-sheet-cancel{display:none}.platform-android .action-sheet-has-icons .button{padding-left:56px}.backdrop{position:fixed;top:0;left:0;z-index:11;width:100%;height:100%;background-color:rgba(0,0,0,.4);visibility:hidden;opacity:0;-webkit-transition:.1s opacity linear;transition:.1s opacity linear}.backdrop.visible{visibility:visible}.backdrop.active{opacity:1}.bar{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:absolute;right:0;left:0;z-index:9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:5px;width:100%;height:44px;border-width:0;border-style:solid;border-top:1px solid transparent;border-bottom:1px solid #ddd;background-color:#fff;background-size:0}@media (min--moz-device-pixel-ratio:1.5),(-webkit-min-device-pixel-ratio:1.5),(min-device-pixel-ratio:1.5),(min-resolution:144dpi),(min-resolution:1.5dppx){.bar{border:none;background-image:linear-gradient(0deg,#ddd,#ddd 50%,transparent 50%);background-position:bottom;background-size:100% 1px;background-repeat:no-repeat}}.bar.bar-clear{border:none;background:0 0;color:#fff}.bar.bar-clear .button,.bar.bar-clear .title{color:#fff}.bar.item-input-inset .item-input-wrapper{margin-top:-1px}.bar.item-input-inset .item-input-wrapper input{padding-left:8px;width:94%;height:28px;background:0 0}.bar.bar-light{border-color:#ddd;background-color:#fff;background-image:linear-gradient(0deg,#ddd,#ddd 50%,transparent 50%);color:#444}.bar.bar-light .title{color:#444}.bar.bar-light.bar-footer{background-image:linear-gradient(180deg,#ddd,#ddd 50%,transparent 50%)}.bar.bar-stable{border-color:#b2b2b2;background-color:#f8f8f8;background-image:linear-gradient(0deg,#b2b2b2,#b2b2b2 50%,transparent 50%);color:#444}.bar.bar-stable .title{color:#444}.bar.bar-stable.bar-footer{background-image:linear-gradient(180deg,#b2b2b2,#b2b2b2 50%,transparent 50%)}.bar.bar-positive{border-color:#0c60ee;background-color:#387ef5;background-image:linear-gradient(0deg,#0c60ee,#0c60ee 50%,transparent 50%);color:#fff}.bar.bar-positive .title{color:#fff}.bar.bar-positive.bar-footer{background-image:linear-gradient(180deg,#0c60ee,#0c60ee 50%,transparent 50%)}.bar.bar-calm{border-color:#0a9dc7;background-color:#11c1f3;background-image:linear-gradient(0deg,#0a9dc7,#0a9dc7 50%,transparent 50%);color:#fff}.bar.bar-calm .title{color:#fff}.bar.bar-calm.bar-footer{background-image:linear-gradient(180deg,#0a9dc7,#0a9dc7 50%,transparent 50%)}.bar.bar-assertive{border-color:#e42112;background-color:#ef473a;background-image:linear-gradient(0deg,#e42112,#e42112 50%,transparent 50%);color:#fff}.bar.bar-assertive .title{color:#fff}.bar.bar-assertive.bar-footer{background-image:linear-gradient(180deg,#e42112,#e42112 50%,transparent 50%)}.bar.bar-balanced{border-color:#28a54c;background-color:#33cd5f;background-image:linear-gradient(0deg,#28a54c,#28a54c 50%,transparent 50%);color:#fff}.bar.bar-balanced .title{color:#fff}.bar.bar-balanced.bar-footer{background-image:linear-gradient(180deg,#28a54c,#28a54c 50%,transparent 50%)}.bar.bar-energized{border-color:#e6b500;background-color:#ffc900;background-image:linear-gradient(0deg,#e6b500,#e6b500 50%,transparent 50%);color:#fff}.bar.bar-energized .title{color:#fff}.bar.bar-energized.bar-footer{background-image:linear-gradient(180deg,#e6b500,#e6b500 50%,transparent 50%)}.bar.bar-royal{border-color:#6b46e5;background-color:#886aea;background-image:linear-gradient(0deg,#6b46e5,#6b46e5 50%,transparent 50%);color:#fff}.bar.bar-royal .title{color:#fff}.bar.bar-royal.bar-footer{background-image:linear-gradient(180deg,#6b46e5,#6b46e5 50%,transparent 50%)}.bar.bar-dark{border-color:#111;background-color:#444;background-image:linear-gradient(0deg,#111,#111 50%,transparent 50%);color:#fff}.bar.bar-dark .title{color:#fff}.bar.bar-dark.bar-footer{background-image:linear-gradient(180deg,#111,#111 50%,transparent 50%)}.bar .title{display:block;position:absolute;top:0;right:0;left:0;z-index:0;overflow:hidden;margin:0 10px;min-width:30px;height:43px;text-align:center;text-overflow:ellipsis;white-space:nowrap;font-size:17px;font-weight:500;line-height:44px}.bar .title.title-left{text-align:left}.bar .title.title-right{text-align:right}.bar .title a{color:inherit}.bar .button,.bar button{z-index:1;padding:0 8px;min-width:initial;min-height:31px;font-weight:400;font-size:13px;line-height:32px}.bar .button .icon:before,.bar .button.button-icon:before,.bar .button.icon-left:before,.bar .button.icon-right:before,.bar .button.icon:before,.bar button .icon:before,.bar button.button-icon:before,.bar button.icon-left:before,.bar button.icon-right:before,.bar button.icon:before{padding-right:2px;padding-left:2px;font-size:20px;line-height:32px}.bar .button.button-icon,.bar button.button-icon{font-size:17px}.bar .button.button-icon .icon:before,.bar .button.button-icon.icon-left:before,.bar .button.button-icon.icon-right:before,.bar .button.button-icon:before,.bar button.button-icon .icon:before,.bar button.button-icon.icon-left:before,.bar button.button-icon.icon-right:before,.bar button.button-icon:before{vertical-align:top;font-size:32px;line-height:32px}.bar .button.button-clear,.bar button.button-clear{padding-right:2px;padding-left:2px;font-weight:300;font-size:17px}.bar .button.button-clear .icon:before,.bar .button.button-clear.icon-left:before,.bar .button.button-clear.icon-right:before,.bar .button.button-clear.icon:before,.bar button.button-clear .icon:before,.bar button.button-clear.icon-left:before,.bar button.button-clear.icon-right:before,.bar button.button-clear.icon:before{font-size:32px;line-height:32px}.bar .button.back-button,.bar button.back-button{display:block;margin-right:5px;padding:0;white-space:nowrap;font-weight:400}.bar .button.back-button.activated,.bar .button.back-button.active,.bar button.back-button.activated,.bar button.back-button.active{opacity:.2}.bar .button-bar>.button,.bar .buttons>.button{min-height:31px;line-height:32px}.bar .button+.button-bar,.bar .button-bar+.button{margin-left:5px}.bar .buttons,.bar .buttons.primary-buttons,.bar .buttons.secondary-buttons{display:inherit}.bar .buttons span{display:inline-block}.bar .buttons-left span{margin-right:5px;display:inherit}.bar .buttons-right span{margin-left:5px;display:inherit}.bar .buttons.pull-right,.bar .title+.button:last-child,.bar .title+.buttons,.bar>.button+.button:last-child,.bar>.button.pull-right{position:absolute;top:5px;right:5px;bottom:5px}.platform-android .nav-bar-has-subheader .bar{background-image:none}.platform-android .bar .back-button .icon:before{font-size:24px}.platform-android .bar .title{font-size:19px;line-height:44px}.bar-light .button{border-color:#ddd;background-color:#fff;color:#444}.bar-light .button:hover{color:#444;text-decoration:none}.bar-light .button.activated,.bar-light .button.active{border-color:#ccc;background-color:#fafafa}.bar-light .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#444;font-size:17px}.bar-light .button.button-icon{border-color:transparent;background:0 0}.bar-stable .button{border-color:#b2b2b2;background-color:#f8f8f8;color:#444}.bar-stable .button:hover{color:#444;text-decoration:none}.bar-stable .button.activated,.bar-stable .button.active{border-color:#a2a2a2;background-color:#e5e5e5}.bar-stable .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#444;font-size:17px}.bar-stable .button.button-icon{border-color:transparent;background:0 0}.bar-positive .button{border-color:#0c60ee;background-color:#387ef5;color:#fff}.bar-positive .button:hover{color:#fff;text-decoration:none}.bar-positive .button.activated,.bar-positive .button.active{border-color:#0c60ee;background-color:#0c60ee}.bar-positive .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-positive .button.button-icon{border-color:transparent;background:0 0}.bar-calm .button{border-color:#0a9dc7;background-color:#11c1f3;color:#fff}.bar-calm .button:hover{color:#fff;text-decoration:none}.bar-calm .button.activated,.bar-calm .button.active{border-color:#0a9dc7;background-color:#0a9dc7}.bar-calm .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-calm .button.button-icon{border-color:transparent;background:0 0}.bar-assertive .button{border-color:#e42112;background-color:#ef473a;color:#fff}.bar-assertive .button:hover{color:#fff;text-decoration:none}.bar-assertive .button.activated,.bar-assertive .button.active{border-color:#e42112;background-color:#e42112}.bar-assertive .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-assertive .button.button-icon{border-color:transparent;background:0 0}.bar-balanced .button{border-color:#28a54c;background-color:#33cd5f;color:#fff}.bar-balanced .button:hover{color:#fff;text-decoration:none}.bar-balanced .button.activated,.bar-balanced .button.active{border-color:#28a54c;background-color:#28a54c}.bar-balanced .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-balanced .button.button-icon{border-color:transparent;background:0 0}.bar-energized .button{border-color:#e6b500;background-color:#ffc900;color:#fff}.bar-energized .button:hover{color:#fff;text-decoration:none}.bar-energized .button.activated,.bar-energized .button.active{border-color:#e6b500;background-color:#e6b500}.bar-energized .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-energized .button.button-icon{border-color:transparent;background:0 0}.bar-royal .button{border-color:#6b46e5;background-color:#886aea;color:#fff}.bar-royal .button:hover{color:#fff;text-decoration:none}.bar-royal .button.activated,.bar-royal .button.active{border-color:#6b46e5;background-color:#6b46e5}.bar-royal .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-royal .button.button-icon{border-color:transparent;background:0 0}.bar-dark .button{border-color:#111;background-color:#444;color:#fff}.bar-dark .button:hover{color:#fff;text-decoration:none}.bar-dark .button.activated,.bar-dark .button.active{border-color:#000;background-color:#262626}.bar-dark .button.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#fff;font-size:17px}.bar-dark .button.button-icon{border-color:transparent;background:0 0}.bar-header{top:0;border-top-width:0;border-bottom-width:1px}.bar-header.has-tabs-top,.tabs-top .bar-header{border-bottom-width:0;background-image:none}.bar-footer{bottom:0;border-top-width:1px;border-bottom-width:0;background-position:top;height:44px}.bar-footer.item-input-inset{position:absolute}.bar-footer .title{height:43px;line-height:44px}.bar-tabs{padding:0}.bar-subheader{top:44px;height:44px}.bar-subheader .title{height:43px;line-height:44px}.bar-subfooter{bottom:44px;height:44px}.bar-subfooter .title{height:43px;line-height:44px}.nav-bar-block{position:absolute;top:0;right:0;left:0;z-index:9}.bar .back-button.hide,.bar .buttons .hide{display:none}.nav-bar-tabs-top .bar{background-image:none}.tabs{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-direction:normal;-webkit-box-orient:horizontal;-webkit-flex-direction:horizontal;-moz-flex-direction:horizontal;-ms-flex-direction:horizontal;flex-direction:horizontal;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;-moz-justify-content:center;justify-content:center;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);border-color:#b2b2b2;background-color:#f8f8f8;background-image:linear-gradient(0deg,#b2b2b2,#b2b2b2 50%,transparent 50%);color:#444;position:absolute;bottom:0;z-index:5;width:100%;height:49px;border-style:solid;border-top-width:1px;background-size:0;line-height:49px}.tabs .tab-item .badge{background-color:#444;color:#f8f8f8}@media (min--moz-device-pixel-ratio:1.5),(-webkit-min-device-pixel-ratio:1.5),(min-device-pixel-ratio:1.5),(min-resolution:144dpi),(min-resolution:1.5dppx){.tabs{padding-top:2px;border-top:none!important;border-bottom:none;background-position:top;background-size:100% 1px;background-repeat:no-repeat}}.tabs-light>.tabs,.tabs.tabs-light{border-color:#ddd;background-color:#fff;background-image:linear-gradient(0deg,#ddd,#ddd 50%,transparent 50%);color:#444}.tabs-light>.tabs .tab-item .badge,.tabs.tabs-light .tab-item .badge{background-color:#444;color:#fff}.tabs-stable>.tabs,.tabs.tabs-stable{border-color:#b2b2b2;background-color:#f8f8f8;background-image:linear-gradient(0deg,#b2b2b2,#b2b2b2 50%,transparent 50%);color:#444}.tabs-stable>.tabs .tab-item .badge,.tabs.tabs-stable .tab-item .badge{background-color:#444;color:#f8f8f8}.tabs-positive>.tabs,.tabs.tabs-positive{border-color:#0c60ee;background-color:#387ef5;background-image:linear-gradient(0deg,#0c60ee,#0c60ee 50%,transparent 50%);color:#fff}.tabs-positive>.tabs .tab-item .badge,.tabs.tabs-positive .tab-item .badge{background-color:#fff;color:#387ef5}.tabs-calm>.tabs,.tabs.tabs-calm{border-color:#0a9dc7;background-color:#11c1f3;background-image:linear-gradient(0deg,#0a9dc7,#0a9dc7 50%,transparent 50%);color:#fff}.tabs-calm>.tabs .tab-item .badge,.tabs.tabs-calm .tab-item .badge{background-color:#fff;color:#11c1f3}.tabs-assertive>.tabs,.tabs.tabs-assertive{border-color:#e42112;background-color:#ef473a;background-image:linear-gradient(0deg,#e42112,#e42112 50%,transparent 50%);color:#fff}.tabs-assertive>.tabs .tab-item .badge,.tabs.tabs-assertive .tab-item .badge{background-color:#fff;color:#ef473a}.tabs-balanced>.tabs,.tabs.tabs-balanced{border-color:#28a54c;background-color:#33cd5f;background-image:linear-gradient(0deg,#28a54c,#28a54c 50%,transparent 50%);color:#fff}.tabs-balanced>.tabs .tab-item .badge,.tabs.tabs-balanced .tab-item .badge{background-color:#fff;color:#33cd5f}.tabs-energized>.tabs,.tabs.tabs-energized{border-color:#e6b500;background-color:#ffc900;background-image:linear-gradient(0deg,#e6b500,#e6b500 50%,transparent 50%);color:#fff}.tabs-energized>.tabs .tab-item .badge,.tabs.tabs-energized .tab-item .badge{background-color:#fff;color:#ffc900}.tabs-royal>.tabs,.tabs.tabs-royal{border-color:#6b46e5;background-color:#886aea;background-image:linear-gradient(0deg,#6b46e5,#6b46e5 50%,transparent 50%);color:#fff}.tabs-royal>.tabs .tab-item .badge,.tabs.tabs-royal .tab-item .badge{background-color:#fff;color:#886aea}.tabs-dark>.tabs,.tabs.tabs-dark{border-color:#111;background-color:#444;background-image:linear-gradient(0deg,#111,#111 50%,transparent 50%);color:#fff}.tabs-dark>.tabs .tab-item .badge,.tabs.tabs-dark .tab-item .badge{background-color:#fff;color:#444}.tabs-striped .tabs{background-color:#fff;background-image:none;border:none;border-bottom:1px solid #ddd;padding-top:2px}.tabs-striped .tab-item.activated,.tabs-striped .tab-item.active,.tabs-striped .tab-item.tab-item-active{margin-top:-2px;border-style:solid;border-width:2px 0 0 0;border-color:#444}.tabs-striped .tab-item.activated .badge,.tabs-striped .tab-item.active .badge,.tabs-striped .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-light .tabs{background-color:#fff}.tabs-striped.tabs-light .tab-item{color:rgba(68,68,68,.4);opacity:1}.tabs-striped.tabs-light .tab-item .badge{opacity:.4}.tabs-striped.tabs-light .tab-item.activated,.tabs-striped.tabs-light .tab-item.active,.tabs-striped.tabs-light .tab-item.tab-item-active{margin-top:-2px;color:#444;border-style:solid;border-width:2px 0 0 0;border-color:#444}.tabs-striped.tabs-stable .tabs{background-color:#f8f8f8}.tabs-striped.tabs-stable .tab-item{color:rgba(68,68,68,.4);opacity:1}.tabs-striped.tabs-stable .tab-item .badge{opacity:.4}.tabs-striped.tabs-stable .tab-item.activated,.tabs-striped.tabs-stable .tab-item.active,.tabs-striped.tabs-stable .tab-item.tab-item-active{margin-top:-2px;color:#444;border-style:solid;border-width:2px 0 0 0;border-color:#444}.tabs-striped.tabs-positive .tabs{background-color:#387ef5}.tabs-striped.tabs-positive .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-positive .tab-item .badge{opacity:.4}.tabs-striped.tabs-positive .tab-item.activated,.tabs-striped.tabs-positive .tab-item.active,.tabs-striped.tabs-positive .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-calm .tabs{background-color:#11c1f3}.tabs-striped.tabs-calm .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-calm .tab-item .badge{opacity:.4}.tabs-striped.tabs-calm .tab-item.activated,.tabs-striped.tabs-calm .tab-item.active,.tabs-striped.tabs-calm .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-assertive .tabs{background-color:#ef473a}.tabs-striped.tabs-assertive .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-assertive .tab-item .badge{opacity:.4}.tabs-striped.tabs-assertive .tab-item.activated,.tabs-striped.tabs-assertive .tab-item.active,.tabs-striped.tabs-assertive .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-balanced .tabs{background-color:#33cd5f}.tabs-striped.tabs-balanced .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-balanced .tab-item .badge{opacity:.4}.tabs-striped.tabs-balanced .tab-item.activated,.tabs-striped.tabs-balanced .tab-item.active,.tabs-striped.tabs-balanced .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-energized .tabs{background-color:#ffc900}.tabs-striped.tabs-energized .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-energized .tab-item .badge{opacity:.4}.tabs-striped.tabs-energized .tab-item.activated,.tabs-striped.tabs-energized .tab-item.active,.tabs-striped.tabs-energized .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-royal .tabs{background-color:#886aea}.tabs-striped.tabs-royal .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-royal .tab-item .badge{opacity:.4}.tabs-striped.tabs-royal .tab-item.activated,.tabs-striped.tabs-royal .tab-item.active,.tabs-striped.tabs-royal .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-dark .tabs{background-color:#444}.tabs-striped.tabs-dark .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-dark .tab-item .badge{opacity:.4}.tabs-striped.tabs-dark .tab-item.activated,.tabs-striped.tabs-dark .tab-item.active,.tabs-striped.tabs-dark .tab-item.tab-item-active{margin-top:-2px;color:#fff;border-style:solid;border-width:2px 0 0 0;border-color:#fff}.tabs-striped.tabs-top .tab-item.activated .badge,.tabs-striped.tabs-top .tab-item.active .badge,.tabs-striped.tabs-top .tab-item.tab-item-active .badge{top:4%}.tabs-striped.tabs-background-light .tabs{background-color:#fff;background-image:none}.tabs-striped.tabs-background-stable .tabs{background-color:#f8f8f8;background-image:none}.tabs-striped.tabs-background-positive .tabs{background-color:#387ef5;background-image:none}.tabs-striped.tabs-background-calm .tabs{background-color:#11c1f3;background-image:none}.tabs-striped.tabs-background-assertive .tabs{background-color:#ef473a;background-image:none}.tabs-striped.tabs-background-balanced .tabs{background-color:#33cd5f;background-image:none}.tabs-striped.tabs-background-energized .tabs{background-color:#ffc900;background-image:none}.tabs-striped.tabs-background-royal .tabs{background-color:#886aea;background-image:none}.tabs-striped.tabs-background-dark .tabs{background-color:#444;background-image:none}.tabs-striped.tabs-color-light .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-striped.tabs-color-light .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-light .tab-item.activated,.tabs-striped.tabs-color-light .tab-item.active,.tabs-striped.tabs-color-light .tab-item.tab-item-active{margin-top:-2px;color:#fff;border:0 solid #fff;border-top-width:2px}.tabs-striped.tabs-color-light .tab-item.activated .badge,.tabs-striped.tabs-color-light .tab-item.active .badge,.tabs-striped.tabs-color-light .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-stable .tab-item{color:rgba(248,248,248,.4);opacity:1}.tabs-striped.tabs-color-stable .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-stable .tab-item.activated,.tabs-striped.tabs-color-stable .tab-item.active,.tabs-striped.tabs-color-stable .tab-item.tab-item-active{margin-top:-2px;color:#f8f8f8;border:0 solid #f8f8f8;border-top-width:2px}.tabs-striped.tabs-color-stable .tab-item.activated .badge,.tabs-striped.tabs-color-stable .tab-item.active .badge,.tabs-striped.tabs-color-stable .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-positive .tab-item{color:rgba(56,126,245,.4);opacity:1}.tabs-striped.tabs-color-positive .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-positive .tab-item.activated,.tabs-striped.tabs-color-positive .tab-item.active,.tabs-striped.tabs-color-positive .tab-item.tab-item-active{margin-top:-2px;color:#387ef5;border:0 solid #387ef5;border-top-width:2px}.tabs-striped.tabs-color-positive .tab-item.activated .badge,.tabs-striped.tabs-color-positive .tab-item.active .badge,.tabs-striped.tabs-color-positive .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-calm .tab-item{color:rgba(17,193,243,.4);opacity:1}.tabs-striped.tabs-color-calm .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-calm .tab-item.activated,.tabs-striped.tabs-color-calm .tab-item.active,.tabs-striped.tabs-color-calm .tab-item.tab-item-active{margin-top:-2px;color:#11c1f3;border:0 solid #11c1f3;border-top-width:2px}.tabs-striped.tabs-color-calm .tab-item.activated .badge,.tabs-striped.tabs-color-calm .tab-item.active .badge,.tabs-striped.tabs-color-calm .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-assertive .tab-item{color:rgba(239,71,58,.4);opacity:1}.tabs-striped.tabs-color-assertive .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-assertive .tab-item.activated,.tabs-striped.tabs-color-assertive .tab-item.active,.tabs-striped.tabs-color-assertive .tab-item.tab-item-active{margin-top:-2px;color:#ef473a;border:0 solid #ef473a;border-top-width:2px}.tabs-striped.tabs-color-assertive .tab-item.activated .badge,.tabs-striped.tabs-color-assertive .tab-item.active .badge,.tabs-striped.tabs-color-assertive .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-balanced .tab-item{color:rgba(51,205,95,.4);opacity:1}.tabs-striped.tabs-color-balanced .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-balanced .tab-item.activated,.tabs-striped.tabs-color-balanced .tab-item.active,.tabs-striped.tabs-color-balanced .tab-item.tab-item-active{margin-top:-2px;color:#33cd5f;border:0 solid #33cd5f;border-top-width:2px}.tabs-striped.tabs-color-balanced .tab-item.activated .badge,.tabs-striped.tabs-color-balanced .tab-item.active .badge,.tabs-striped.tabs-color-balanced .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-energized .tab-item{color:rgba(255,201,0,.4);opacity:1}.tabs-striped.tabs-color-energized .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-energized .tab-item.activated,.tabs-striped.tabs-color-energized .tab-item.active,.tabs-striped.tabs-color-energized .tab-item.tab-item-active{margin-top:-2px;color:#ffc900;border:0 solid #ffc900;border-top-width:2px}.tabs-striped.tabs-color-energized .tab-item.activated .badge,.tabs-striped.tabs-color-energized .tab-item.active .badge,.tabs-striped.tabs-color-energized .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-royal .tab-item{color:rgba(136,106,234,.4);opacity:1}.tabs-striped.tabs-color-royal .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-royal .tab-item.activated,.tabs-striped.tabs-color-royal .tab-item.active,.tabs-striped.tabs-color-royal .tab-item.tab-item-active{margin-top:-2px;color:#886aea;border:0 solid #886aea;border-top-width:2px}.tabs-striped.tabs-color-royal .tab-item.activated .badge,.tabs-striped.tabs-color-royal .tab-item.active .badge,.tabs-striped.tabs-color-royal .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-striped.tabs-color-dark .tab-item{color:rgba(68,68,68,.4);opacity:1}.tabs-striped.tabs-color-dark .tab-item .badge{opacity:.4}.tabs-striped.tabs-color-dark .tab-item.activated,.tabs-striped.tabs-color-dark .tab-item.active,.tabs-striped.tabs-color-dark .tab-item.tab-item-active{margin-top:-2px;color:#444;border:0 solid #444;border-top-width:2px}.tabs-striped.tabs-color-dark .tab-item.activated .badge,.tabs-striped.tabs-color-dark .tab-item.active .badge,.tabs-striped.tabs-color-dark .tab-item.tab-item-active .badge{top:2px;opacity:1}.tabs-background-light .tabs,.tabs-background-light>.tabs{background-color:#fff;background-image:linear-gradient(0deg,#ddd,#ddd 50%,transparent 50%);border-color:#ddd}.tabs-background-stable .tabs,.tabs-background-stable>.tabs{background-color:#f8f8f8;background-image:linear-gradient(0deg,#b2b2b2,#b2b2b2 50%,transparent 50%);border-color:#b2b2b2}.tabs-background-positive .tabs,.tabs-background-positive>.tabs{background-color:#387ef5;background-image:linear-gradient(0deg,#0c60ee,#0c60ee 50%,transparent 50%);border-color:#0c60ee}.tabs-background-calm .tabs,.tabs-background-calm>.tabs{background-color:#11c1f3;background-image:linear-gradient(0deg,#0a9dc7,#0a9dc7 50%,transparent 50%);border-color:#0a9dc7}.tabs-background-assertive .tabs,.tabs-background-assertive>.tabs{background-color:#ef473a;background-image:linear-gradient(0deg,#e42112,#e42112 50%,transparent 50%);border-color:#e42112}.tabs-background-balanced .tabs,.tabs-background-balanced>.tabs{background-color:#33cd5f;background-image:linear-gradient(0deg,#28a54c,#28a54c 50%,transparent 50%);border-color:#28a54c}.tabs-background-energized .tabs,.tabs-background-energized>.tabs{background-color:#ffc900;background-image:linear-gradient(0deg,#e6b500,#e6b500 50%,transparent 50%);border-color:#e6b500}.tabs-background-royal .tabs,.tabs-background-royal>.tabs{background-color:#886aea;background-image:linear-gradient(0deg,#6b46e5,#6b46e5 50%,transparent 50%);border-color:#6b46e5}.tabs-background-dark .tabs,.tabs-background-dark>.tabs{background-color:#444;background-image:linear-gradient(0deg,#111,#111 50%,transparent 50%);border-color:#111}.tabs-color-light .tab-item{color:rgba(255,255,255,.4);opacity:1}.tabs-color-light .tab-item .badge{opacity:.4}.tabs-color-light .tab-item.activated,.tabs-color-light .tab-item.active,.tabs-color-light .tab-item.tab-item-active{color:#fff;border:0 solid #fff}.tabs-color-light .tab-item.activated .badge,.tabs-color-light .tab-item.active .badge,.tabs-color-light .tab-item.tab-item-active .badge{opacity:1}.tabs-color-stable .tab-item{color:rgba(248,248,248,.4);opacity:1}.tabs-color-stable .tab-item .badge{opacity:.4}.tabs-color-stable .tab-item.activated,.tabs-color-stable .tab-item.active,.tabs-color-stable .tab-item.tab-item-active{color:#f8f8f8;border:0 solid #f8f8f8}.tabs-color-stable .tab-item.activated .badge,.tabs-color-stable .tab-item.active .badge,.tabs-color-stable .tab-item.tab-item-active .badge{opacity:1}.tabs-color-positive .tab-item{color:rgba(56,126,245,.4);opacity:1}.tabs-color-positive .tab-item .badge{opacity:.4}.tabs-color-positive .tab-item.activated,.tabs-color-positive .tab-item.active,.tabs-color-positive .tab-item.tab-item-active{color:#387ef5;border:0 solid #387ef5}.tabs-color-positive .tab-item.activated .badge,.tabs-color-positive .tab-item.active .badge,.tabs-color-positive .tab-item.tab-item-active .badge{opacity:1}.tabs-color-calm .tab-item{color:rgba(17,193,243,.4);opacity:1}.tabs-color-calm .tab-item .badge{opacity:.4}.tabs-color-calm .tab-item.activated,.tabs-color-calm .tab-item.active,.tabs-color-calm .tab-item.tab-item-active{color:#11c1f3;border:0 solid #11c1f3}.tabs-color-calm .tab-item.activated .badge,.tabs-color-calm .tab-item.active .badge,.tabs-color-calm .tab-item.tab-item-active .badge{opacity:1}.tabs-color-assertive .tab-item{color:rgba(239,71,58,.4);opacity:1}.tabs-color-assertive .tab-item .badge{opacity:.4}.tabs-color-assertive .tab-item.activated,.tabs-color-assertive .tab-item.active,.tabs-color-assertive .tab-item.tab-item-active{color:#ef473a;border:0 solid #ef473a}.tabs-color-assertive .tab-item.activated .badge,.tabs-color-assertive .tab-item.active .badge,.tabs-color-assertive .tab-item.tab-item-active .badge{opacity:1}.tabs-color-balanced .tab-item{color:rgba(51,205,95,.4);opacity:1}.tabs-color-balanced .tab-item .badge{opacity:.4}.tabs-color-balanced .tab-item.activated,.tabs-color-balanced .tab-item.active,.tabs-color-balanced .tab-item.tab-item-active{color:#33cd5f;border:0 solid #33cd5f}.tabs-color-balanced .tab-item.activated .badge,.tabs-color-balanced .tab-item.active .badge,.tabs-color-balanced .tab-item.tab-item-active .badge{opacity:1}.tabs-color-energized .tab-item{color:rgba(255,201,0,.4);opacity:1}.tabs-color-energized .tab-item .badge{opacity:.4}.tabs-color-energized .tab-item.activated,.tabs-color-energized .tab-item.active,.tabs-color-energized .tab-item.tab-item-active{color:#ffc900;border:0 solid #ffc900}.tabs-color-energized .tab-item.activated .badge,.tabs-color-energized .tab-item.active .badge,.tabs-color-energized .tab-item.tab-item-active .badge{opacity:1}.tabs-color-royal .tab-item{color:rgba(136,106,234,.4);opacity:1}.tabs-color-royal .tab-item .badge{opacity:.4}.tabs-color-royal .tab-item.activated,.tabs-color-royal .tab-item.active,.tabs-color-royal .tab-item.tab-item-active{color:#886aea;border:0 solid #886aea}.tabs-color-royal .tab-item.activated .badge,.tabs-color-royal .tab-item.active .badge,.tabs-color-royal .tab-item.tab-item-active .badge{opacity:1}.tabs-color-dark .tab-item{color:rgba(68,68,68,.4);opacity:1}.tabs-color-dark .tab-item .badge{opacity:.4}.tabs-color-dark .tab-item.activated,.tabs-color-dark .tab-item.active,.tabs-color-dark .tab-item.tab-item-active{color:#444;border:0 solid #444}.tabs-color-dark .tab-item.activated .badge,.tabs-color-dark .tab-item.active .badge,.tabs-color-dark .tab-item.tab-item-active .badge{opacity:1}ion-tabs.tabs-color-active-light .tab-item{color:#444}ion-tabs.tabs-color-active-light .tab-item.activated,ion-tabs.tabs-color-active-light .tab-item.active,ion-tabs.tabs-color-active-light .tab-item.tab-item-active{color:#fff}ion-tabs.tabs-striped.tabs-color-active-light .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-light .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-light .tab-item.tab-item-active{border-color:#fff;color:#fff}ion-tabs.tabs-color-active-stable .tab-item{color:#444}ion-tabs.tabs-color-active-stable .tab-item.activated,ion-tabs.tabs-color-active-stable .tab-item.active,ion-tabs.tabs-color-active-stable .tab-item.tab-item-active{color:#f8f8f8}ion-tabs.tabs-striped.tabs-color-active-stable .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-stable .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-stable .tab-item.tab-item-active{border-color:#f8f8f8;color:#f8f8f8}ion-tabs.tabs-color-active-positive .tab-item{color:#444}ion-tabs.tabs-color-active-positive .tab-item.activated,ion-tabs.tabs-color-active-positive .tab-item.active,ion-tabs.tabs-color-active-positive .tab-item.tab-item-active{color:#387ef5}ion-tabs.tabs-striped.tabs-color-active-positive .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-positive .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-positive .tab-item.tab-item-active{border-color:#387ef5;color:#387ef5}ion-tabs.tabs-color-active-calm .tab-item{color:#444}ion-tabs.tabs-color-active-calm .tab-item.activated,ion-tabs.tabs-color-active-calm .tab-item.active,ion-tabs.tabs-color-active-calm .tab-item.tab-item-active{color:#11c1f3}ion-tabs.tabs-striped.tabs-color-active-calm .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-calm .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-calm .tab-item.tab-item-active{border-color:#11c1f3;color:#11c1f3}ion-tabs.tabs-color-active-assertive .tab-item{color:#444}ion-tabs.tabs-color-active-assertive .tab-item.activated,ion-tabs.tabs-color-active-assertive .tab-item.active,ion-tabs.tabs-color-active-assertive .tab-item.tab-item-active{color:#ef473a}ion-tabs.tabs-striped.tabs-color-active-assertive .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-assertive .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-assertive .tab-item.tab-item-active{border-color:#ef473a;color:#ef473a}ion-tabs.tabs-color-active-balanced .tab-item{color:#444}ion-tabs.tabs-color-active-balanced .tab-item.activated,ion-tabs.tabs-color-active-balanced .tab-item.active,ion-tabs.tabs-color-active-balanced .tab-item.tab-item-active{color:#33cd5f}ion-tabs.tabs-striped.tabs-color-active-balanced .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-balanced .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-balanced .tab-item.tab-item-active{border-color:#33cd5f;color:#33cd5f}ion-tabs.tabs-color-active-energized .tab-item{color:#444}ion-tabs.tabs-color-active-energized .tab-item.activated,ion-tabs.tabs-color-active-energized .tab-item.active,ion-tabs.tabs-color-active-energized .tab-item.tab-item-active{color:#ffc900}ion-tabs.tabs-striped.tabs-color-active-energized .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-energized .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-energized .tab-item.tab-item-active{border-color:#ffc900;color:#ffc900}ion-tabs.tabs-color-active-royal .tab-item{color:#444}ion-tabs.tabs-color-active-royal .tab-item.activated,ion-tabs.tabs-color-active-royal .tab-item.active,ion-tabs.tabs-color-active-royal .tab-item.tab-item-active{color:#886aea}ion-tabs.tabs-striped.tabs-color-active-royal .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-royal .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-royal .tab-item.tab-item-active{border-color:#886aea;color:#886aea}ion-tabs.tabs-color-active-dark .tab-item{color:#fff}ion-tabs.tabs-color-active-dark .tab-item.activated,ion-tabs.tabs-color-active-dark .tab-item.active,ion-tabs.tabs-color-active-dark .tab-item.tab-item-active{color:#444}ion-tabs.tabs-striped.tabs-color-active-dark .tab-item.activated,ion-tabs.tabs-striped.tabs-color-active-dark .tab-item.active,ion-tabs.tabs-striped.tabs-color-active-dark .tab-item.tab-item-active{border-color:#444;color:#444}.tabs-top.tabs-striped{padding-bottom:0}.tabs-top.tabs-striped .tab-item{background:0 0;-webkit-transition:color .1s ease;-moz-transition:color .1s ease;-ms-transition:color .1s ease;-o-transition:color .1s ease;transition:color .1s ease}.tabs-top.tabs-striped .tab-item.activated,.tabs-top.tabs-striped .tab-item.active,.tabs-top.tabs-striped .tab-item.tab-item-active{margin-top:1px;border-width:0 0 2px 0!important;border-style:solid}.tabs-top.tabs-striped .tab-item.activated>.badge,.tabs-top.tabs-striped .tab-item.activated>i,.tabs-top.tabs-striped .tab-item.active>.badge,.tabs-top.tabs-striped .tab-item.active>i,.tabs-top.tabs-striped .tab-item.tab-item-active>.badge,.tabs-top.tabs-striped .tab-item.tab-item-active>i{margin-top:-1px}.tabs-top.tabs-striped .tab-item .badge{-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease}.tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.activated .tab-title,.tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.activated i,.tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.active .tab-title,.tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.active i,.tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.tab-item-active .tab-title,.tabs-top.tabs-striped:not(.tabs-icon-left):not(.tabs-icon-top) .tab-item.tab-item-active i{display:block;margin-top:-1px}.tabs-top.tabs-striped.tabs-icon-left .tab-item{margin-top:1px}.tabs-top.tabs-striped.tabs-icon-left .tab-item.activated .tab-title,.tabs-top.tabs-striped.tabs-icon-left .tab-item.activated i,.tabs-top.tabs-striped.tabs-icon-left .tab-item.active .tab-title,.tabs-top.tabs-striped.tabs-icon-left .tab-item.active i,.tabs-top.tabs-striped.tabs-icon-left .tab-item.tab-item-active .tab-title,.tabs-top.tabs-striped.tabs-icon-left .tab-item.tab-item-active i{margin-top:-.1em}.tabs-top>.tabs,.tabs.tabs-top{top:44px;padding-top:0;background-position:bottom;border-top-width:0;border-bottom-width:1px}.tabs-top>.tabs .tab-item.activated .badge,.tabs-top>.tabs .tab-item.active .badge,.tabs-top>.tabs .tab-item.tab-item-active .badge,.tabs.tabs-top .tab-item.activated .badge,.tabs.tabs-top .tab-item.active .badge,.tabs.tabs-top .tab-item.tab-item-active .badge{top:4%}.tabs-top~.bar-header{border-bottom-width:0}.tab-item{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;display:block;overflow:hidden;max-width:150px;height:100%;color:inherit;text-align:center;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;font-weight:400;font-size:14px;font-family:"-apple-system","Helvetica Neue",Roboto,"Segoe UI",sans-serif;opacity:.7}.tab-item:hover{cursor:pointer}.tab-item.tab-hidden,.tabs-item-hide>.tabs,.tabs.tabs-item-hide{display:none}.tabs-icon-bottom.tabs .tab-item,.tabs-icon-bottom>.tabs .tab-item,.tabs-icon-top.tabs .tab-item,.tabs-icon-top>.tabs .tab-item{font-size:10px;line-height:14px}.tab-item .icon{display:block;margin:0 auto;height:32px;font-size:32px}.tabs-icon-left.tabs .tab-item,.tabs-icon-left>.tabs .tab-item,.tabs-icon-right.tabs .tab-item,.tabs-icon-right>.tabs .tab-item{font-size:10px}.tabs-icon-left.tabs .tab-item .icon,.tabs-icon-left.tabs .tab-item .tab-title,.tabs-icon-left>.tabs .tab-item .icon,.tabs-icon-left>.tabs .tab-item .tab-title,.tabs-icon-right.tabs .tab-item .icon,.tabs-icon-right.tabs .tab-item .tab-title,.tabs-icon-right>.tabs .tab-item .icon,.tabs-icon-right>.tabs .tab-item .tab-title{display:inline-block;vertical-align:top;margin-top:-.1em}.tabs-icon-left.tabs .tab-item .icon:before,.tabs-icon-left.tabs .tab-item .tab-title:before,.tabs-icon-left>.tabs .tab-item .icon:before,.tabs-icon-left>.tabs .tab-item .tab-title:before,.tabs-icon-right.tabs .tab-item .icon:before,.tabs-icon-right.tabs .tab-item .tab-title:before,.tabs-icon-right>.tabs .tab-item .icon:before,.tabs-icon-right>.tabs .tab-item .tab-title:before{font-size:24px;line-height:49px}.tabs-icon-left.tabs .tab-item .icon,.tabs-icon-left>.tabs .tab-item .icon{padding-right:3px}.tabs-icon-right.tabs .tab-item .icon,.tabs-icon-right>.tabs .tab-item .icon{padding-left:3px}.tabs-icon-only.tabs .icon,.tabs-icon-only>.tabs .icon{line-height:inherit}.tab-item.has-badge{position:relative}.tab-item .badge{position:absolute;top:4%;right:33%;right:calc(50% - 26px);padding:1px 6px;height:auto;font-size:12px;line-height:16px}.tab-item.activated,.tab-item.active,.tab-item.tab-item-active{opacity:1}.tab-item.activated.tab-item-light,.tab-item.active.tab-item-light,.tab-item.tab-item-active.tab-item-light{color:#fff}.tab-item.activated.tab-item-stable,.tab-item.active.tab-item-stable,.tab-item.tab-item-active.tab-item-stable{color:#f8f8f8}.tab-item.activated.tab-item-positive,.tab-item.active.tab-item-positive,.tab-item.tab-item-active.tab-item-positive{color:#387ef5}.tab-item.activated.tab-item-calm,.tab-item.active.tab-item-calm,.tab-item.tab-item-active.tab-item-calm{color:#11c1f3}.tab-item.activated.tab-item-assertive,.tab-item.active.tab-item-assertive,.tab-item.tab-item-active.tab-item-assertive{color:#ef473a}.tab-item.activated.tab-item-balanced,.tab-item.active.tab-item-balanced,.tab-item.tab-item-active.tab-item-balanced{color:#33cd5f}.tab-item.activated.tab-item-energized,.tab-item.active.tab-item-energized,.tab-item.tab-item-active.tab-item-energized{color:#ffc900}.tab-item.activated.tab-item-royal,.tab-item.active.tab-item-royal,.tab-item.tab-item-active.tab-item-royal{color:#886aea}.tab-item.activated.tab-item-dark,.tab-item.active.tab-item-dark,.tab-item.tab-item-active.tab-item-dark{color:#444}.item.tabs{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;padding:0}.item.tabs .icon:before{position:relative}.tab-item.disabled,.tab-item[disabled]{opacity:.4;cursor:default;pointer-events:none}.nav-bar-tabs-top.hide~.view-container .tabs-top .tabs{top:0}.pane[hide-nav-bar=true] .has-tabs-top{top:49px}.menu{position:absolute;top:0;bottom:0;z-index:0;overflow:hidden;min-height:100%;max-height:100%;width:275px;background-color:#fff}.menu .scroll-content{z-index:10}.menu .bar-header{z-index:11}.menu-content{-webkit-transform:none;transform:none;box-shadow:-1px 0 2px rgba(0,0,0,.2),1px 0 2px rgba(0,0,0,.2)}.menu-open .menu-content .pane,.menu-open .menu-content .scroll-content,.menu-open .menu-content .scroll-content .scroll{pointer-events:none}.menu-open .menu-content .scroll-content:not(.overflow-scroll){overflow:hidden}.grade-b .menu-content,.grade-c .menu-content{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;right:-1px;left:-1px;border-right:1px solid #ccc;border-left:1px solid #ccc;box-shadow:none}.menu-left{left:0}.menu-right{right:0}.aside-open.aside-resizing .menu-right{display:none}.menu-animated{-webkit-transition:-webkit-transform 200ms ease;transition:transform 200ms ease}.modal-backdrop,.modal-backdrop-bg{position:fixed;top:0;left:0;z-index:10;width:100%;height:100%}.modal-backdrop-bg{pointer-events:none}.modal{display:block;position:absolute;top:0;z-index:10;overflow:hidden;min-height:100%;width:100%;background-color:#fff}@media (min-width:680px){.modal{top:20%;right:20%;bottom:20%;left:20%;min-height:240px;width:60%}.modal.ng-leave-active{bottom:0}.platform-ios.platform-cordova .modal-wrapper .modal .bar-header:not(.bar-subheader){height:44px}.platform-ios.platform-cordova .modal-wrapper .modal .bar-header:not(.bar-subheader)>*{margin-top:0}.platform-ios.platform-cordova .modal-wrapper .modal .bar-subheader,.platform-ios.platform-cordova .modal-wrapper .modal .has-header,.platform-ios.platform-cordova .modal-wrapper .modal .tabs-top>.tabs,.platform-ios.platform-cordova .modal-wrapper .modal .tabs.tabs-top{top:44px}.platform-ios.platform-cordova .modal-wrapper .modal .has-subheader{top:88px}.platform-ios.platform-cordova .modal-wrapper .modal .has-header.has-tabs-top{top:93px}.platform-ios.platform-cordova .modal-wrapper .modal .has-header.has-subheader.has-tabs-top{top:137px}.modal-backdrop-bg{-webkit-transition:opacity 300ms ease-in-out;transition:opacity 300ms ease-in-out;background-color:#000;opacity:0}.active .modal-backdrop-bg{opacity:.5}}.modal-open{pointer-events:none}.modal-open .modal,.modal-open .modal-backdrop{pointer-events:auto}.modal-open.loading-active .modal,.modal-open.loading-active .modal-backdrop{pointer-events:none}.popover-backdrop{position:fixed;top:0;left:0;z-index:10;width:100%;height:100%;background-color:transparent}.popover-backdrop.active{background-color:rgba(0,0,0,.1)}.popover{position:absolute;top:25%;left:50%;z-index:10;display:block;margin-top:12px;margin-left:-110px;height:280px;width:220px;background-color:#fff;box-shadow:0 1px 3px rgba(0,0,0,.4);opacity:0}.popover .item:first-child{border-top:0}.popover .item:last-child{border-bottom:0}.popover.popover-bottom{margin-top:-12px}.popover,.popover .bar-header{border-radius:2px}.popover .scroll-content{z-index:1;margin:2px 0}.popover .bar-header{border-bottom-right-radius:0;border-bottom-left-radius:0}.popover .has-header{border-top-right-radius:0;border-top-left-radius:0}.popover-arrow{display:none}.platform-ios .popover{box-shadow:0 0 40px rgba(0,0,0,.08);border-radius:10px}.platform-ios .popover .bar-header{-webkit-border-top-right-radius:10px;border-top-right-radius:10px;-webkit-border-top-left-radius:10px;border-top-left-radius:10px}.platform-ios .popover .scroll-content{margin:8px 0;border-radius:10px}.platform-ios .popover .scroll-content.has-header{margin-top:0}.platform-ios .popover-arrow{position:absolute;display:block;top:-17px;width:30px;height:19px;overflow:hidden}.platform-ios .popover-arrow:after{position:absolute;top:12px;left:5px;width:20px;height:20px;background-color:#fff;border-radius:3px;content:'';-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.platform-ios .popover-bottom .popover-arrow{top:auto;bottom:-10px}.platform-ios .popover-bottom .popover-arrow:after{top:-6px}.platform-android .popover{margin-top:-32px;background-color:#fafafa;box-shadow:0 2px 6px rgba(0,0,0,.35)}.platform-android .popover .item{border-color:#fafafa;background-color:#fafafa;color:#4d4d4d}.platform-android .popover.popover-bottom{margin-top:32px}.platform-android .popover-backdrop,.platform-android .popover-backdrop.active{background-color:transparent}.popover-open{pointer-events:none}.popover-open .popover,.popover-open .popover-backdrop{pointer-events:auto}.popover-open.loading-active .popover,.popover-open.loading-active .popover-backdrop{pointer-events:none}@media (min-width:680px){.popover{width:360px;margin-left:-180px}}.popup-container{position:absolute;top:0;left:0;bottom:0;right:0;background:0 0;display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;-moz-justify-content:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;z-index:12;visibility:hidden}.popup-container.popup-showing{visibility:visible}.popup-container.popup-hidden .popup{-webkit-animation-name:scaleOut;animation-name:scaleOut;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.popup-container.active .popup{-webkit-animation-name:superScaleIn;animation-name:superScaleIn;-webkit-animation-duration:.2s;animation-duration:.2s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.popup-container .popup{width:250px;max-width:100%;max-height:90%;border-radius:0;background-color:rgba(255,255,255,.9);display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;-moz-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.popup-container input,.popup-container textarea{width:100%}.popup-head{padding:15px 10px;border-bottom:1px solid #eee;text-align:center}.popup-title{margin:0;padding:0;font-size:15px}.popup-sub-title{margin:5px 0 0 0;padding:0;font-weight:400;font-size:11px}.popup-body{padding:10px;overflow:auto}.popup-buttons{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-direction:normal;-webkit-box-orient:horizontal;-webkit-flex-direction:row;-moz-flex-direction:row;-ms-flex-direction:row;flex-direction:row;padding:10px;min-height:65px}.popup-buttons .button{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;display:block;min-height:45px;border-radius:2px;line-height:20px;margin-right:5px}.popup-buttons .button:last-child{margin-right:0}.popup-open,.popup-open.modal-open .modal{pointer-events:none}.popup-open .popup,.popup-open .popup-backdrop{pointer-events:auto}.loading-container{position:absolute;left:0;top:0;right:0;bottom:0;z-index:13;display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;-moz-justify-content:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;-webkit-transition:.2s opacity linear;transition:.2s opacity linear;visibility:hidden;opacity:0}.loading-container:not(.visible) .icon,.loading-container:not(.visible) .spinner{display:none}.loading-container.visible{visibility:visible}.loading-container.active{opacity:1}.loading-container .loading{padding:20px;border-radius:5px;background-color:rgba(0,0,0,.7);color:#fff;text-align:center;text-overflow:ellipsis;font-size:15px}.loading-container .loading h1,.loading-container .loading h2,.loading-container .loading h3,.loading-container .loading h4,.loading-container .loading h5,.loading-container .loading h6{color:#fff}.item{border-color:#ddd;background-color:#fff;color:#444;position:relative;z-index:2;display:block;margin:-1px;padding:16px;border-width:1px;border-style:solid;font-size:16px}.item h2{margin:0 0 2px 0;font-size:16px;font-weight:400}.item h3{margin:0 0 4px 0;font-size:14px}.item h4{margin:0 0 4px 0;font-size:12px}.item h5,.item h6{margin:0 0 3px 0;font-size:10px}.item p{color:#666;font-size:14px;margin-bottom:2px}.item h1:last-child,.item h2:last-child,.item h3:last-child,.item h4:last-child,.item h5:last-child,.item h6:last-child,.item p:last-child{margin-bottom:0}.item .badge{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;position:absolute;top:16px;right:32px}.item.item-button-right .badge{right:67px}.item.item-divider .badge{top:8px}.item .badge+.badge{margin-right:5px}.item.item-light{border-color:#ddd;background-color:#fff;color:#444}.item.item-stable{border-color:#b2b2b2;background-color:#f8f8f8;color:#444}.item.item-positive{border-color:#0c60ee;background-color:#387ef5;color:#fff}.item.item-calm{border-color:#0a9dc7;background-color:#11c1f3;color:#fff}.item.item-assertive{border-color:#e42112;background-color:#ef473a;color:#fff}.item.item-balanced{border-color:#28a54c;background-color:#33cd5f;color:#fff}.item.item-energized{border-color:#e6b500;background-color:#ffc900;color:#fff}.item.item-royal{border-color:#6b46e5;background-color:#886aea;color:#fff}.item.item-dark{border-color:#111;background-color:#444;color:#fff}.item[ng-click]:hover{cursor:pointer}.item-borderless,.list-borderless .item{border-width:0}.item .item-content.activated,.item .item-content.activated.item-complex>.item-content,.item .item-content.active,.item .item-content.active.item-complex>.item-content,.item-complex.activated .item-content,.item-complex.activated .item-content.item-complex>.item-content,.item-complex.active .item-content,.item-complex.active .item-content.item-complex>.item-content,.item.activated,.item.activated.item-complex>.item-content,.item.active,.item.active.item-complex>.item-content{border-color:#ccc;background-color:#D9D9D9}.item .item-content.activated.item-light,.item .item-content.activated.item-light.item-complex>.item-content,.item .item-content.active.item-light,.item .item-content.active.item-light.item-complex>.item-content,.item-complex.activated .item-content.item-light,.item-complex.activated .item-content.item-light.item-complex>.item-content,.item-complex.active .item-content.item-light,.item-complex.active .item-content.item-light.item-complex>.item-content,.item.activated.item-light,.item.activated.item-light.item-complex>.item-content,.item.active.item-light,.item.active.item-light.item-complex>.item-content{border-color:#ccc;background-color:#fafafa}.item .item-content.activated.item-stable,.item .item-content.activated.item-stable.item-complex>.item-content,.item .item-content.active.item-stable,.item .item-content.active.item-stable.item-complex>.item-content,.item-complex.activated .item-content.item-stable,.item-complex.activated .item-content.item-stable.item-complex>.item-content,.item-complex.active .item-content.item-stable,.item-complex.active .item-content.item-stable.item-complex>.item-content,.item.activated.item-stable,.item.activated.item-stable.item-complex>.item-content,.item.active.item-stable,.item.active.item-stable.item-complex>.item-content{border-color:#a2a2a2;background-color:#e5e5e5}.item .item-content.activated.item-positive,.item .item-content.activated.item-positive.item-complex>.item-content,.item .item-content.active.item-positive,.item .item-content.active.item-positive.item-complex>.item-content,.item-complex.activated .item-content.item-positive,.item-complex.activated .item-content.item-positive.item-complex>.item-content,.item-complex.active .item-content.item-positive,.item-complex.active .item-content.item-positive.item-complex>.item-content,.item.activated.item-positive,.item.activated.item-positive.item-complex>.item-content,.item.active.item-positive,.item.active.item-positive.item-complex>.item-content{border-color:#0c60ee;background-color:#0c60ee}.item .item-content.activated.item-calm,.item .item-content.activated.item-calm.item-complex>.item-content,.item .item-content.active.item-calm,.item .item-content.active.item-calm.item-complex>.item-content,.item-complex.activated .item-content.item-calm,.item-complex.activated .item-content.item-calm.item-complex>.item-content,.item-complex.active .item-content.item-calm,.item-complex.active .item-content.item-calm.item-complex>.item-content,.item.activated.item-calm,.item.activated.item-calm.item-complex>.item-content,.item.active.item-calm,.item.active.item-calm.item-complex>.item-content{border-color:#0a9dc7;background-color:#0a9dc7}.item .item-content.activated.item-assertive,.item .item-content.activated.item-assertive.item-complex>.item-content,.item .item-content.active.item-assertive,.item .item-content.active.item-assertive.item-complex>.item-content,.item-complex.activated .item-content.item-assertive,.item-complex.activated .item-content.item-assertive.item-complex>.item-content,.item-complex.active .item-content.item-assertive,.item-complex.active .item-content.item-assertive.item-complex>.item-content,.item.activated.item-assertive,.item.activated.item-assertive.item-complex>.item-content,.item.active.item-assertive,.item.active.item-assertive.item-complex>.item-content{border-color:#e42112;background-color:#e42112}.item .item-content.activated.item-balanced,.item .item-content.activated.item-balanced.item-complex>.item-content,.item .item-content.active.item-balanced,.item .item-content.active.item-balanced.item-complex>.item-content,.item-complex.activated .item-content.item-balanced,.item-complex.activated .item-content.item-balanced.item-complex>.item-content,.item-complex.active .item-content.item-balanced,.item-complex.active .item-content.item-balanced.item-complex>.item-content,.item.activated.item-balanced,.item.activated.item-balanced.item-complex>.item-content,.item.active.item-balanced,.item.active.item-balanced.item-complex>.item-content{border-color:#28a54c;background-color:#28a54c}.item .item-content.activated.item-energized,.item .item-content.activated.item-energized.item-complex>.item-content,.item .item-content.active.item-energized,.item .item-content.active.item-energized.item-complex>.item-content,.item-complex.activated .item-content.item-energized,.item-complex.activated .item-content.item-energized.item-complex>.item-content,.item-complex.active .item-content.item-energized,.item-complex.active .item-content.item-energized.item-complex>.item-content,.item.activated.item-energized,.item.activated.item-energized.item-complex>.item-content,.item.active.item-energized,.item.active.item-energized.item-complex>.item-content{border-color:#e6b500;background-color:#e6b500}.item .item-content.activated.item-royal,.item .item-content.activated.item-royal.item-complex>.item-content,.item .item-content.active.item-royal,.item .item-content.active.item-royal.item-complex>.item-content,.item-complex.activated .item-content.item-royal,.item-complex.activated .item-content.item-royal.item-complex>.item-content,.item-complex.active .item-content.item-royal,.item-complex.active .item-content.item-royal.item-complex>.item-content,.item.activated.item-royal,.item.activated.item-royal.item-complex>.item-content,.item.active.item-royal,.item.active.item-royal.item-complex>.item-content{border-color:#6b46e5;background-color:#6b46e5}.item .item-content.activated.item-dark,.item .item-content.activated.item-dark.item-complex>.item-content,.item .item-content.active.item-dark,.item .item-content.active.item-dark.item-complex>.item-content,.item-complex.activated .item-content.item-dark,.item-complex.activated .item-content.item-dark.item-complex>.item-content,.item-complex.active .item-content.item-dark,.item-complex.active .item-content.item-dark.item-complex>.item-content,.item.activated.item-dark,.item.activated.item-dark.item-complex>.item-content,.item.active.item-dark,.item.active.item-dark.item-complex>.item-content{border-color:#000;background-color:#262626}.item,.item h1,.item h2,.item h3,.item h4,.item h5,.item h6,.item p,.item-content,.item-content h1,.item-content h2,.item-content h3,.item-content h4,.item-content h5,.item-content h6,.item-content p{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}a.item{color:inherit;text-decoration:none}a.item:focus,a.item:hover{text-decoration:none}.item-complex,a.item.item-complex,button.item.item-complex{padding:0}.item-complex .item-content,.item-radio .item-content{position:relative;z-index:2;padding:16px 49px 16px 16px;border:none;background-color:#fff}a.item-content{display:block;color:inherit;text-decoration:none}.item-body h1,.item-body h2,.item-body h3,.item-body h4,.item-body h5,.item-body h6,.item-body p,.item-complex.item-text-wrap,.item-complex.item-text-wrap .item-content,.item-complex.item-text-wrap h1,.item-complex.item-text-wrap h2,.item-complex.item-text-wrap h3,.item-complex.item-text-wrap h4,.item-complex.item-text-wrap h5,.item-complex.item-text-wrap h6,.item-complex.item-text-wrap p,.item-text-wrap,.item-text-wrap .item,.item-text-wrap .item-content,.item-text-wrap h1,.item-text-wrap h2,.item-text-wrap h3,.item-text-wrap h4,.item-text-wrap h5,.item-text-wrap h6,.item-text-wrap p{overflow:visible;white-space:normal}.item-complex.item-light>.item-content{border-color:#ddd;background-color:#fff;color:#444}.item-complex.item-light>.item-content.active,.item-complex.item-light>.item-content.active.item-complex>.item-content,.item-complex.item-light>.item-content:active,.item-complex.item-light>.item-content:active.item-complex>.item-content{border-color:#ccc;background-color:#fafafa}.item-complex.item-stable>.item-content{border-color:#b2b2b2;background-color:#f8f8f8;color:#444}.item-complex.item-stable>.item-content.active,.item-complex.item-stable>.item-content.active.item-complex>.item-content,.item-complex.item-stable>.item-content:active,.item-complex.item-stable>.item-content:active.item-complex>.item-content{border-color:#a2a2a2;background-color:#e5e5e5}.item-complex.item-positive>.item-content{border-color:#0c60ee;background-color:#387ef5;color:#fff}.item-complex.item-positive>.item-content.active,.item-complex.item-positive>.item-content.active.item-complex>.item-content,.item-complex.item-positive>.item-content:active,.item-complex.item-positive>.item-content:active.item-complex>.item-content{border-color:#0c60ee;background-color:#0c60ee}.item-complex.item-calm>.item-content{border-color:#0a9dc7;background-color:#11c1f3;color:#fff}.item-complex.item-calm>.item-content.active,.item-complex.item-calm>.item-content.active.item-complex>.item-content,.item-complex.item-calm>.item-content:active,.item-complex.item-calm>.item-content:active.item-complex>.item-content{border-color:#0a9dc7;background-color:#0a9dc7}.item-complex.item-assertive>.item-content{border-color:#e42112;background-color:#ef473a;color:#fff}.item-complex.item-assertive>.item-content.active,.item-complex.item-assertive>.item-content.active.item-complex>.item-content,.item-complex.item-assertive>.item-content:active,.item-complex.item-assertive>.item-content:active.item-complex>.item-content{border-color:#e42112;background-color:#e42112}.item-complex.item-balanced>.item-content{border-color:#28a54c;background-color:#33cd5f;color:#fff}.item-complex.item-balanced>.item-content.active,.item-complex.item-balanced>.item-content.active.item-complex>.item-content,.item-complex.item-balanced>.item-content:active,.item-complex.item-balanced>.item-content:active.item-complex>.item-content{border-color:#28a54c;background-color:#28a54c}.item-complex.item-energized>.item-content{border-color:#e6b500;background-color:#ffc900;color:#fff}.item-complex.item-energized>.item-content.active,.item-complex.item-energized>.item-content.active.item-complex>.item-content,.item-complex.item-energized>.item-content:active,.item-complex.item-energized>.item-content:active.item-complex>.item-content{border-color:#e6b500;background-color:#e6b500}.item-complex.item-royal>.item-content{border-color:#6b46e5;background-color:#886aea;color:#fff}.item-complex.item-royal>.item-content.active,.item-complex.item-royal>.item-content.active.item-complex>.item-content,.item-complex.item-royal>.item-content:active,.item-complex.item-royal>.item-content:active.item-complex>.item-content{border-color:#6b46e5;background-color:#6b46e5}.item-complex.item-dark>.item-content{border-color:#111;background-color:#444;color:#fff}.item-complex.item-dark>.item-content.active,.item-complex.item-dark>.item-content.active.item-complex>.item-content,.item-complex.item-dark>.item-content:active,.item-complex.item-dark>.item-content:active.item-complex>.item-content{border-color:#000;background-color:#262626}.item-icon-left .icon,.item-icon-right .icon{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:absolute;top:0;height:100%;font-size:32px}.item-icon-left .icon:before,.item-icon-right .icon:before{display:block;width:32px;text-align:center}.item .fill-icon{min-width:30px;min-height:30px;font-size:28px}.item-icon-left{padding-left:54px}.item-icon-left .icon{left:11px}.item-complex.item-icon-left{padding-left:0}.item-complex.item-icon-left .item-content{padding-left:54px}.item-icon-right{padding-right:54px}.item-icon-right .icon{right:11px}.item-complex.item-icon-right{padding-right:0}.item-complex.item-icon-right .item-content{padding-right:54px}.item-icon-left.item-icon-right .icon:first-child{right:auto}.item-icon-left .item-delete .icon,.item-icon-left.item-icon-right .icon:last-child{left:auto}.item-icon-left .icon-accessory,.item-icon-right .icon-accessory{color:#ccc;font-size:16px}.item-icon-left .icon-accessory{left:3px}.item-icon-right .icon-accessory{right:3px}.item-button-left{padding-left:72px}.item-button-left .item-content>.button,.item-button-left>.button{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:absolute;top:8px;left:11px;min-width:34px;min-height:34px;font-size:18px;line-height:32px}.item-button-left .item-content>.button .icon:before,.item-button-left>.button .icon:before{position:relative;left:auto;width:auto;line-height:31px}.item-button-left .item-content>.button>.button,.item-button-left>.button>.button{margin:0 2px;min-height:34px;font-size:18px;line-height:32px}.item-button-right,a.item.item-button-right,button.item.item-button-right{padding-right:80px}.item-button-right .item-content>.button,.item-button-right .item-content>.buttons,.item-button-right>.button,.item-button-right>.buttons{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:absolute;top:8px;right:16px;min-width:34px;min-height:34px;font-size:18px;line-height:32px}.item-button-right .item-content>.button .icon:before,.item-button-right .item-content>.buttons .icon:before,.item-button-right>.button .icon:before,.item-button-right>.buttons .icon:before{position:relative;left:auto;width:auto;line-height:31px}.item-button-right .item-content>.button>.button,.item-button-right .item-content>.buttons>.button,.item-button-right>.button>.button,.item-button-right>.buttons>.button{margin:0 2px;min-width:34px;min-height:34px;font-size:18px;line-height:32px}.item-button-left.item-button-right .button:first-child{right:auto}.item-button-left.item-button-right .button:last-child{left:auto}.item-avatar,.item-avatar .item-content,.item-avatar-left,.item-avatar-left .item-content{padding-left:72px;min-height:72px}.item-avatar .item-content .item-image,.item-avatar .item-content>img:first-child,.item-avatar .item-image,.item-avatar-left .item-content .item-image,.item-avatar-left .item-content>img:first-child,.item-avatar-left .item-image,.item-avatar-left>img:first-child,.item-avatar>img:first-child{position:absolute;top:16px;left:16px;max-width:40px;max-height:40px;width:100%;height:100%;border-radius:50%}.item-avatar-right,.item-avatar-right .item-content{padding-right:72px;min-height:72px}.item-avatar-right .item-content .item-image,.item-avatar-right .item-content>img:first-child,.item-avatar-right .item-image,.item-avatar-right>img:first-child{position:absolute;top:16px;right:16px;max-width:40px;max-height:40px;width:100%;height:100%;border-radius:50%}.item-thumbnail-left,.item-thumbnail-left .item-content{padding-top:8px;padding-left:106px;min-height:100px}.item-thumbnail-left .item-content .item-image,.item-thumbnail-left .item-content>img:first-child,.item-thumbnail-left .item-image,.item-thumbnail-left>img:first-child{position:absolute;top:10px;left:10px;max-width:80px;max-height:80px;width:100%;height:100%}.item-avatar-left.item-complex,.item-avatar.item-complex,.item-thumbnail-left.item-complex{padding-top:0;padding-left:0}.item-thumbnail-right,.item-thumbnail-right .item-content{padding-top:8px;padding-right:106px;min-height:100px}.item-thumbnail-right .item-content .item-image,.item-thumbnail-right .item-content>img:first-child,.item-thumbnail-right .item-image,.item-thumbnail-right>img:first-child{position:absolute;top:10px;right:10px;max-width:80px;max-height:80px;width:100%;height:100%}.item-avatar-right.item-complex,.item-thumbnail-right.item-complex{padding-top:0;padding-right:0}.item-image{padding:0;text-align:center}.item-image .list-img,.item-image img:first-child{width:100%;vertical-align:middle}.item-body{overflow:auto;padding:16px;text-overflow:inherit;white-space:normal}.item-body h1,.item-body h2,.item-body h3,.item-body h4,.item-body h5,.item-body h6,.item-body p{margin-top:16px;margin-bottom:16px}.item-divider{padding-top:8px;padding-bottom:8px;min-height:30px;background-color:#f5f5f5;color:#222;font-weight:500}.item-divider-ios,.platform-ios .item-divider-platform{padding-top:26px;text-transform:uppercase;font-weight:300;font-size:13px;background-color:#efeff4;color:#555}.item-divider-android,.platform-android .item-divider-platform{font-weight:300;font-size:13px}.item-note{float:right;color:#aaa;font-size:14px}.item-left-editable .item-content,.item-right-editable .item-content{-webkit-transition-duration:250ms;transition-duration:250ms;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-property:-webkit-transform;-moz-transition-property:-moz-transform;transition-property:transform}.item-left-editing.item-left-editable .item-content,.list-left-editing .item-left-editable .item-content{-webkit-transform:translate3d(50px,0,0);transform:translate3d(50px,0,0)}.item-remove-animate.ng-leave{-webkit-transition-duration:300ms;transition-duration:300ms}.item-remove-animate.ng-leave .item-content,.item-remove-animate.ng-leave:last-of-type{-webkit-transition-duration:300ms;transition-duration:300ms;-webkit-transition-timing-function:ease-in;transition-timing-function:ease-in;-webkit-transition-property:all;transition-property:all}.item-remove-animate.ng-leave.ng-leave-active .item-content{opacity:0;-webkit-transform:translate3d(-100%,0,0)!important;transform:translate3d(-100%,0,0)!important}.item-remove-animate.ng-leave.ng-leave-active:last-of-type{opacity:0}.item-remove-animate.ng-leave.ng-leave-active~ion-item:not(.ng-leave){-webkit-transform:translate3d(0,-webkit-calc(-100% + 1px),0);transform:translate3d(0,calc(-100% + 1px),0);-webkit-transition-duration:300ms;transition-duration:300ms;-webkit-transition-timing-function:cubic-bezier(.25,.81,.24,1);transition-timing-function:cubic-bezier(.25,.81,.24,1);-webkit-transition-property:all;transition-property:all}.item-left-edit{-webkit-transition:all ease-in-out 125ms;transition:all ease-in-out 125ms;position:absolute;top:0;left:0;z-index:0;width:50px;height:100%;line-height:100%;display:none;opacity:0;-webkit-transform:translate3d(-21px,0,0);transform:translate3d(-21px,0,0)}.item-left-edit .button{height:100%}.item-left-edit .button.icon{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:absolute;top:0;height:100%}.item-left-edit.visible{display:block}.item-left-edit.visible.active{opacity:1;-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}.list-left-editing .item-left-edit{-webkit-transition-delay:125ms;transition-delay:125ms}.item-delete .button.icon{color:#ef473a;font-size:24px}.item-delete .button.icon:hover{opacity:.7}.item-right-edit{-webkit-transition:all ease-in-out 250ms;transition:all ease-in-out 250ms;position:absolute;top:0;right:0;z-index:3;width:75px;height:100%;background:inherit;padding-left:20px;display:block;opacity:0;-webkit-transform:translate3d(75px,0,0);transform:translate3d(75px,0,0)}.item-right-edit .button{min-width:50px;height:100%}.item-right-edit .button.icon{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:absolute;top:0;height:100%;font-size:32px}.item-right-edit.visible{display:block}.item-right-edit.visible.active{opacity:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.item-reorder .button.icon{color:#444;font-size:32px}.item-reordering{position:absolute;left:0;top:0;z-index:9;width:100%;box-shadow:0 0 10px 0 #aaa}.item-reordering .item-reorder{z-index:9}.item-placeholder{opacity:.7}.item-options{position:absolute;top:0;right:0;z-index:1;height:100%}.item-options .button{height:100%;border:none;border-radius:0;display:-webkit-inline-box;display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center}.item-options .button:before{margin:0 auto}.list{position:relative;padding-top:1px;padding-bottom:1px;padding-left:0;margin-bottom:20px}.list:last-child{margin-bottom:0}.list:last-child.card{margin-bottom:40px}.list-header{margin-top:20px;padding:5px 15px;background-color:transparent;color:#222;font-weight:700}.card.list .list-item{padding-right:1px;padding-left:1px}.card,.list-inset{overflow:hidden;margin:20px 10px;border-radius:2px;background-color:#fff}.card{padding-top:1px;padding-bottom:1px;box-shadow:0 1px 3px rgba(0,0,0,.3)}.card .item{border-left:0;border-right:0}.card .item:first-child{border-top:0}.card .item:last-child{border-bottom:0}.padding .card,.padding .list-inset{margin-left:0;margin-right:0}.card .item:first-child,.card .item:first-child .item-content,.list-inset .item:first-child,.list-inset .item:first-child .item-content,.padding>.list .item:first-child,.padding>.list .item:first-child .item-content{border-top-left-radius:2px;border-top-right-radius:2px}.card .item:last-child,.card .item:last-child .item-content,.list-inset .item:last-child,.list-inset .item:last-child .item-content,.padding>.list .item:last-child,.padding>.list .item:last-child .item-content{border-bottom-right-radius:2px;border-bottom-left-radius:2px}.card .item:last-child,.list-inset .item:last-child{margin-bottom:-1px}.card .item,.list-inset .item,.padding-horizontal>.list .item,.padding>.list .item{margin-right:0;margin-left:0}.card .item.item-input input,.list-inset .item.item-input input,.padding-horizontal>.list .item.item-input input,.padding>.list .item.item-input input{padding-right:44px}.padding-left>.list .item{margin-left:0}.padding-right>.list .item{margin-right:0}.badge{background-color:transparent;color:#AAA;z-index:1;display:inline-block;padding:3px 8px;min-width:10px;border-radius:10px;vertical-align:baseline;text-align:center;white-space:nowrap;font-weight:700;font-size:14px;line-height:16px}.badge:empty{display:none}.badge.badge-light,.tabs .tab-item .badge.badge-light{background-color:#fff;color:#444}.badge.badge-stable,.tabs .tab-item .badge.badge-stable{background-color:#f8f8f8;color:#444}.badge.badge-positive,.tabs .tab-item .badge.badge-positive{background-color:#387ef5;color:#fff}.badge.badge-calm,.tabs .tab-item .badge.badge-calm{background-color:#11c1f3;color:#fff}.badge.badge-assertive,.tabs .tab-item .badge.badge-assertive{background-color:#ef473a;color:#fff}.badge.badge-balanced,.tabs .tab-item .badge.badge-balanced{background-color:#33cd5f;color:#fff}.badge.badge-energized,.tabs .tab-item .badge.badge-energized{background-color:#ffc900;color:#fff}.badge.badge-royal,.tabs .tab-item .badge.badge-royal{background-color:#886aea;color:#fff}.badge.badge-dark,.tabs .tab-item .badge.badge-dark{background-color:#444;color:#fff}.button .badge{position:relative;top:-1px}.slider{position:relative;visibility:hidden;overflow:hidden}.slider-slides{position:relative;height:100%}.slider-slide{position:relative;display:block;float:left;width:100%;height:100%;vertical-align:top}.slider-slide-image>img{width:100%}.slider-pager{position:absolute;bottom:20px;z-index:1;width:100%;height:15px;text-align:center}.slider-pager .slider-pager-page{display:inline-block;margin:0 3px;width:15px;color:#000;text-decoration:none;opacity:.3}.slider-pager .slider-pager-page.active{-webkit-transition:opacity .4s ease-in;transition:opacity .4s ease-in;opacity:1}.slider-pager-page.ng-animate,.slider-pager-page.ng-enter,.slider-pager-page.ng-leave,.slider-slide.ng-animate,.slider-slide.ng-enter,.slider-slide.ng-leave{-webkit-transition:none!important;transition:none!important}.slider-pager-page.ng-animate,.slider-slide.ng-animate{-webkit-animation:none 0s;animation:none 0s}.swiper-container{margin:0 auto;position:relative;z-index:1}.swiper-container-no-flexbox .swiper-slide{float:left}.swiper-container-vertical>.swiper-wrapper{-webkit-box-orient:vertical;-moz-box-orient:vertical;-ms-flex-direction:column;-webkit-flex-direction:column;flex-direction:column}.swiper-wrapper{z-index:1;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex;-webkit-transition-property:-webkit-transform;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.swiper-container-android .swiper-slide,.swiper-wrapper{-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-o-transform:translate(0,0);-ms-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.swiper-container-multirow>.swiper-wrapper{-webkit-box-lines:multiple;-moz-box-lines:multiple;-ms-flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-wrap:wrap}.swiper-container-free-mode>.swiper-wrapper{-webkit-transition-timing-function:ease-out;-moz-transition-timing-function:ease-out;-ms-transition-timing-function:ease-out;-o-transition-timing-function:ease-out;transition-timing-function:ease-out;margin:0 auto}.swiper-slide{display:block;-webkit-flex-shrink:0;-ms-flex:0 0 auto;flex-shrink:0;position:relative}.swiper-container-autoheight,.swiper-container-autoheight .swiper-slide{height:auto}.swiper-container-autoheight .swiper-wrapper{-webkit-box-align:start;-ms-flex-align:start;-webkit-align-items:flex-start;align-items:flex-start;-webkit-transition-property:-webkit-transform,height;-moz-transition-property:-moz-transform;-o-transition-property:-o-transform;-ms-transition-property:-ms-transform;transition-property:transform,height}.swiper-container .swiper-notification{position:absolute;left:0;top:0;pointer-events:none;opacity:0;z-index:-1000}.swiper-wp8-horizontal{-ms-touch-action:pan-y;touch-action:pan-y}.swiper-wp8-vertical{-ms-touch-action:pan-x;touch-action:pan-x}.swiper-button-next,.swiper-button-prev{position:absolute;top:50%;width:27px;height:44px;margin-top:-22px;z-index:10;cursor:pointer;-moz-background-size:27px 44px;-webkit-background-size:27px 44px;background-size:27px 44px;background-position:center;background-repeat:no-repeat}.swiper-button-next.swiper-button-disabled,.swiper-button-prev.swiper-button-disabled{opacity:.35;cursor:auto;pointer-events:none}.swiper-button-prev,.swiper-container-rtl .swiper-button-next{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");left:10px;right:auto}.swiper-button-prev.swiper-button-black,.swiper-container-rtl .swiper-button-next.swiper-button-black{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E")}.swiper-button-prev.swiper-button-white,.swiper-container-rtl .swiper-button-next.swiper-button-white{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E")}.swiper-button-next,.swiper-container-rtl .swiper-button-prev{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");right:10px;left:auto}.swiper-button-next.swiper-button-black,.swiper-container-rtl .swiper-button-prev.swiper-button-black{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E")}.swiper-button-next.swiper-button-white,.swiper-container-rtl .swiper-button-prev.swiper-button-white{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E")}.swiper-pagination{position:absolute;text-align:center;-webkit-transition:300ms;-moz-transition:300ms;-o-transition:300ms;transition:300ms;-webkit-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0);z-index:10}.swiper-pagination.swiper-pagination-hidden{opacity:0}.swiper-pagination-bullet{width:8px;height:8px;display:inline-block;border-radius:100%;background:#000;opacity:.2}button.swiper-pagination-bullet{border:none;margin:0;padding:0;box-shadow:none;-moz-appearance:none;-ms-appearance:none;-webkit-appearance:none;appearance:none}.swiper-pagination-clickable .swiper-pagination-bullet{cursor:pointer}.swiper-pagination-white .swiper-pagination-bullet{background:#fff}.swiper-pagination-bullet-active{opacity:1}.swiper-pagination-white .swiper-pagination-bullet-active{background:#fff}.swiper-pagination-black .swiper-pagination-bullet-active{background:#000}.swiper-container-vertical>.swiper-pagination{right:10px;top:50%;-webkit-transform:translate3d(0,-50%,0);-moz-transform:translate3d(0,-50%,0);-o-transform:translate(0,-50%);-ms-transform:translate3d(0,-50%,0);transform:translate3d(0,-50%,0)}.swiper-container-vertical>.swiper-pagination .swiper-pagination-bullet{margin:5px 0;display:block}.swiper-container-horizontal>.swiper-pagination{bottom:10px;left:0;width:100%}.swiper-container-horizontal>.swiper-pagination .swiper-pagination-bullet{margin:0 5px}.swiper-container-3d{-webkit-perspective:1200px;-moz-perspective:1200px;-o-perspective:1200px;perspective:1200px}.swiper-container-3d .swiper-cube-shadow,.swiper-container-3d .swiper-slide,.swiper-container-3d .swiper-slide-shadow-bottom,.swiper-container-3d .swiper-slide-shadow-left,.swiper-container-3d .swiper-slide-shadow-right,.swiper-container-3d .swiper-slide-shadow-top,.swiper-container-3d .swiper-wrapper{-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;transform-style:preserve-3d}.swiper-container-3d .swiper-slide-shadow-bottom,.swiper-container-3d .swiper-slide-shadow-left,.swiper-container-3d .swiper-slide-shadow-right,.swiper-container-3d .swiper-slide-shadow-top{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none;z-index:10}.swiper-container-3d .swiper-slide-shadow-left{background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(transparent));background-image:-webkit-linear-gradient(right,rgba(0,0,0,.5),transparent);background-image:-moz-linear-gradient(right,rgba(0,0,0,.5),transparent);background-image:-o-linear-gradient(right,rgba(0,0,0,.5),transparent);background-image:linear-gradient(to left,rgba(0,0,0,.5),transparent)}.swiper-container-3d .swiper-slide-shadow-right{background-image:-webkit-gradient(linear,right top,left top,from(rgba(0,0,0,.5)),to(transparent));background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5),transparent);background-image:-moz-linear-gradient(left,rgba(0,0,0,.5),transparent);background-image:-o-linear-gradient(left,rgba(0,0,0,.5),transparent);background-image:linear-gradient(to right,rgba(0,0,0,.5),transparent)}.swiper-container-3d .swiper-slide-shadow-top{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.5)),to(transparent));background-image:-webkit-linear-gradient(bottom,rgba(0,0,0,.5),transparent);background-image:-moz-linear-gradient(bottom,rgba(0,0,0,.5),transparent);background-image:-o-linear-gradient(bottom,rgba(0,0,0,.5),transparent);background-image:linear-gradient(to top,rgba(0,0,0,.5),transparent)}.swiper-container-3d .swiper-slide-shadow-bottom{background-image:-webkit-gradient(linear,left bottom,left top,from(rgba(0,0,0,.5)),to(transparent));background-image:-webkit-linear-gradient(top,rgba(0,0,0,.5),transparent);background-image:-moz-linear-gradient(top,rgba(0,0,0,.5),transparent);background-image:-o-linear-gradient(top,rgba(0,0,0,.5),transparent);background-image:linear-gradient(to bottom,rgba(0,0,0,.5),transparent)}.swiper-container-coverflow .swiper-wrapper{-ms-perspective:1200px}.swiper-container-fade.swiper-container-free-mode .swiper-slide{-webkit-transition-timing-function:ease-out;-moz-transition-timing-function:ease-out;-ms-transition-timing-function:ease-out;-o-transition-timing-function:ease-out;transition-timing-function:ease-out}.swiper-container-fade .swiper-slide,.swiper-container-fade .swiper-slide .swiper-slide{pointer-events:none}.swiper-container-fade .swiper-slide-active,.swiper-container-fade .swiper-slide-active .swiper-slide-active{pointer-events:auto}.swiper-container-cube{overflow:visible}.swiper-container-cube .swiper-slide{pointer-events:none;visibility:hidden;-webkit-transform-origin:0 0;-moz-transform-origin:0 0;-ms-transform-origin:0 0;transform-origin:0 0;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;backface-visibility:hidden;width:100%;height:100%;z-index:1}.swiper-container-cube.swiper-container-rtl .swiper-slide{-webkit-transform-origin:100% 0;-moz-transform-origin:100% 0;-ms-transform-origin:100% 0;transform-origin:100% 0}.swiper-container-cube .swiper-slide-active,.swiper-container-cube .swiper-slide-next,.swiper-container-cube .swiper-slide-next+.swiper-slide,.swiper-container-cube .swiper-slide-prev{pointer-events:auto;visibility:visible}.swiper-container-cube .swiper-slide-shadow-bottom,.swiper-container-cube .swiper-slide-shadow-left,.swiper-container-cube .swiper-slide-shadow-right,.swiper-container-cube .swiper-slide-shadow-top{z-index:0;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;backface-visibility:hidden}.swiper-container-cube .swiper-cube-shadow{position:absolute;left:0;bottom:0;width:100%;height:100%;background:#000;opacity:.6;-webkit-filter:blur(50px);filter:blur(50px);z-index:0}.swiper-scrollbar{border-radius:10px;position:relative;-ms-touch-action:none;background:rgba(0,0,0,.1)}.swiper-container-horizontal>.swiper-scrollbar{position:absolute;left:1%;bottom:3px;z-index:50;height:5px;width:98%}.swiper-container-vertical>.swiper-scrollbar{position:absolute;right:3px;top:1%;z-index:50;width:5px;height:98%}.swiper-scrollbar-drag{height:100%;width:100%;position:relative;background:rgba(0,0,0,.5);border-radius:10px;left:0;top:0}.swiper-scrollbar-cursor-drag{cursor:move}.swiper-lazy-preloader{width:42px;height:42px;position:absolute;left:50%;top:50%;margin-left:-21px;margin-top:-21px;z-index:10;-webkit-transform-origin:50%;-moz-transform-origin:50%;transform-origin:50%;-webkit-animation:swiper-preloader-spin 1s steps(12,end) infinite;-moz-animation:swiper-preloader-spin 1s steps(12,end) infinite;animation:swiper-preloader-spin 1s steps(12,end) infinite}.swiper-lazy-preloader:after{display:block;content:"";width:100%;height:100%;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");background-position:50%;-webkit-background-size:100%;background-size:100%;background-repeat:no-repeat}.swiper-lazy-preloader-white:after{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")}@-webkit-keyframes swiper-preloader-spin{100%{-webkit-transform:rotate(360deg)}}@keyframes swiper-preloader-spin{100%{transform:rotate(360deg)}}ion-slides{width:100%;height:100%;display:block}.slide-zoom{display:block;width:100%;text-align:center}.swiper-container{width:100%;height:100%;padding:0;overflow:hidden}.swiper-wrapper{position:absolute;left:0;top:0;width:100%;height:100%;padding:0}.swiper-slide{width:100%;height:100%;box-sizing:border-box}.swiper-slide img{width:auto;height:auto;max-width:100%;max-height:100%}.scroll-refresher{position:absolute;top:-60px;right:0;left:0;overflow:hidden;margin:auto;height:60px}.scroll-refresher .ionic-refresher-content{position:absolute;bottom:15px;left:0;width:100%;color:#666;text-align:center;font-size:30px}.scroll-refresher .ionic-refresher-content .text-pulling,.scroll-refresher .ionic-refresher-content .text-refreshing{font-size:16px;line-height:16px}.scroll-refresher .ionic-refresher-content.ionic-refresher-with-text{bottom:10px}.scroll-refresher .icon-pulling,.scroll-refresher .icon-refreshing{width:100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.scroll-refresher .icon-pulling{-webkit-animation-name:refresh-spin-back;animation-name:refresh-spin-back;-webkit-animation-duration:200ms;animation-duration:200ms;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:none;animation-fill-mode:none;-webkit-transform:translate3d(0,0,0) rotate(0deg);transform:translate3d(0,0,0) rotate(0deg)}.scroll-refresher .icon-refreshing,.scroll-refresher .text-refreshing{display:none}.scroll-refresher .icon-refreshing{-webkit-animation-duration:1.5s;animation-duration:1.5s}.scroll-refresher.active .icon-pulling:not(.pulling-rotation-disabled){-webkit-animation-name:refresh-spin;animation-name:refresh-spin;-webkit-transform:translate3d(0,0,0) rotate(-180deg);transform:translate3d(0,0,0) rotate(-180deg)}.scroll-refresher.active.refreshing{-webkit-transition:transform .2s;transition:transform .2s;-webkit-transform:scale(1,1);transform:scale(1,1)}.scroll-refresher.active.refreshing .icon-pulling,.scroll-refresher.active.refreshing .text-pulling{display:none}.scroll-refresher.active.refreshing .icon-refreshing,.scroll-refresher.active.refreshing .text-refreshing{display:block}.scroll-refresher.active.refreshing.refreshing-tail{-webkit-transform:scale(0,0);transform:scale(0,0)}.overflow-scroll>.scroll{-webkit-overflow-scrolling:touch;width:100%}.overflow-scroll>.scroll.overscroll{position:fixed;right:0;left:0}.overflow-scroll.padding>.scroll.overscroll{padding:10px}@-webkit-keyframes refresh-spin{0%{-webkit-transform:translate3d(0,0,0) rotate(0)}100%{-webkit-transform:translate3d(0,0,0) rotate(180deg)}}@keyframes refresh-spin{0%{transform:translate3d(0,0,0) rotate(0)}100%{transform:translate3d(0,0,0) rotate(180deg)}}@-webkit-keyframes refresh-spin-back{0%{-webkit-transform:translate3d(0,0,0) rotate(180deg)}100%{-webkit-transform:translate3d(0,0,0) rotate(0)}}@keyframes refresh-spin-back{0%{transform:translate3d(0,0,0) rotate(180deg)}100%{transform:translate3d(0,0,0) rotate(0)}}.spinner{stroke:#444;fill:#444}.spinner svg{width:28px;height:28px}.spinner.spinner-light{stroke:#fff;fill:#fff}.spinner.spinner-stable{stroke:#f8f8f8;fill:#f8f8f8}.spinner.spinner-positive{stroke:#387ef5;fill:#387ef5}.spinner.spinner-calm{stroke:#11c1f3;fill:#11c1f3}.spinner.spinner-balanced{stroke:#33cd5f;fill:#33cd5f}.spinner.spinner-assertive{stroke:#ef473a;fill:#ef473a}.spinner.spinner-energized{stroke:#ffc900;fill:#ffc900}.spinner.spinner-royal{stroke:#886aea;fill:#886aea}.spinner.spinner-dark{stroke:#444;fill:#444}.spinner-android{stroke:#4b8bf4}.spinner-ios,.spinner-ios-small{stroke:#69717d}.spinner-spiral .stop1{stop-color:#fff;stop-opacity:0}.spinner-spiral.spinner-light .stop1{stop-color:#444}.spinner-spiral.spinner-light .stop2{stop-color:#fff}.spinner-spiral.spinner-stable .stop2{stop-color:#f8f8f8}.spinner-spiral.spinner-positive .stop2{stop-color:#387ef5}.spinner-spiral.spinner-calm .stop2{stop-color:#11c1f3}.spinner-spiral.spinner-balanced .stop2{stop-color:#33cd5f}.spinner-spiral.spinner-assertive .stop2{stop-color:#ef473a}.spinner-spiral.spinner-energized .stop2{stop-color:#ffc900}.spinner-spiral.spinner-royal .stop2{stop-color:#886aea}.spinner-spiral.spinner-dark .stop2{stop-color:#444}form{margin:0 0 1.42857}legend{display:block;margin-bottom:1.42857;padding:0;width:100%;border:1px solid #ddd;color:#444;font-size:21px;line-height:2.85714}legend small{color:#f8f8f8;font-size:1.07143}button,input,label,select,textarea{font-weight:400;font-size:14px;line-height:1.42857}button,input,select,textarea{font-family:"-apple-system","Helvetica Neue",Roboto,"Segoe UI",sans-serif}.item-input{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:relative;overflow:hidden;padding:6px 0 5px 16px}.item-input input{-webkit-border-radius:0;border-radius:0;-webkit-box-flex:1;-webkit-flex:1 220px;-moz-box-flex:1;-moz-flex:1 220px;-ms-flex:1 220px;flex:1 220px;-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0;padding-right:24px;background-color:transparent}.item-input .button .icon{-webkit-box-flex:0;-webkit-flex:0 0 24px;-moz-box-flex:0;-moz-flex:0 0 24px;-ms-flex:0 0 24px;flex:0 0 24px;position:static;display:inline-block;height:auto;text-align:center;font-size:16px}.item-input .button-bar{-webkit-border-radius:0;border-radius:0;-webkit-box-flex:1;-webkit-flex:1 0 220px;-moz-box-flex:1;-moz-flex:1 0 220px;-ms-flex:1 0 220px;flex:1 0 220px;-webkit-appearance:none;-moz-appearance:none;appearance:none}.item-input .icon{min-width:14px}.platform-windowsphone .item-input input{flex-shrink:1}.item-input-inset{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;position:relative;overflow:hidden;padding:10.67px}.item-input-wrapper{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex:1 0;-moz-box-flex:1;-moz-flex:1 0;-ms-flex:1 0;flex:1 0;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;-webkit-border-radius:4px;border-radius:4px;padding-right:8px;padding-left:8px;background:#eee}.item-input-inset .item-input-wrapper input{padding-left:4px;height:29px;background:0 0;line-height:18px}.item-input-wrapper~.button{margin-left:10.67px}.input-label{display:table;padding:7px 10px 7px 0;max-width:200px;width:35%;color:#444;font-size:16px}.placeholder-icon{color:#aaa}.placeholder-icon:first-child{padding-right:6px}.placeholder-icon:last-child{padding-left:6px}.item-stacked-label{display:block;background-color:transparent;box-shadow:none}.item-stacked-label .icon,.item-stacked-label .input-label{display:inline-block;padding:4px 0 0 0;vertical-align:middle}.item-stacked-label input,.item-stacked-label textarea{-webkit-border-radius:2px;border-radius:2px;padding:4px 8px 3px 0;border:none;background-color:#fff}.item-stacked-label input{overflow:hidden;height:46px}.item-select.item-stacked-label select{position:relative;padding:0;max-width:90%;direction:ltr;white-space:pre-wrap;margin:-3px}.item-floating-label{display:block;background-color:transparent;box-shadow:none}.item-floating-label .input-label{position:relative;padding:5px 0 0 0;opacity:0;top:10px;-webkit-transition:opacity .15s ease-in,top .2s linear;transition:opacity .15s ease-in,top .2s linear}.item-floating-label .input-label.has-input{opacity:1;top:0;-webkit-transition:opacity .15s ease-in,top .2s linear;transition:opacity .15s ease-in,top .2s linear}input[type=search],input[type=text],input[type=password],input[type=datetime],input[type=datetime-local],input[type=date],input[type=month],input[type=time],input[type=week],input[type=number],input[type=email],input[type=url],input[type=tel],input[type=color],textarea{display:block;padding-top:2px;padding-left:0;height:34px;color:#111;vertical-align:middle;font-size:14px;line-height:16px}.platform-android input[type=datetime-local],.platform-android input[type=date],.platform-android input[type=month],.platform-android input[type=time],.platform-android input[type=week],.platform-ios input[type=datetime-local],.platform-ios input[type=date],.platform-ios input[type=month],.platform-ios input[type=time],.platform-ios input[type=week]{padding-top:8px}.item-input input,.item-input textarea{width:100%}textarea{padding-left:0}textarea::-moz-placeholder{color:#aaa}textarea:-ms-input-placeholder{color:#aaa}textarea::-webkit-input-placeholder{color:#aaa;text-indent:-3px}textarea{height:auto}input[type=search],input[type=text],input[type=password],input[type=datetime],input[type=datetime-local],input[type=date],input[type=month],input[type=time],input[type=week],input[type=number],input[type=email],input[type=url],input[type=tel],input[type=color],textarea{border:0}input[type=radio],input[type=checkbox]{margin:0;line-height:normal}.item-input input[type=button],.item-input input[type=reset],.item-input input[type=submit],.item-input input[type=radio],.item-input input[type=checkbox],.item-input input[type=file],.item-input input[type=image]{width:auto}input[type=file]{line-height:34px}.cloned-text-input+input,.cloned-text-input+textarea,.previous-input-focus{position:absolute!important;left:-9999px;width:200px}input::-moz-placeholder,textarea::-moz-placeholder{color:#aaa}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#aaa}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#aaa;text-indent:0}input[disabled],input[readonly]:not(.cloned-text-input),select[disabled],select[readonly],textarea[disabled],textarea[readonly]:not(.cloned-text-input){background-color:#f8f8f8;cursor:not-allowed}input[type=radio][disabled],input[type=radio][readonly],input[type=checkbox][disabled],input[type=checkbox][readonly]{background-color:transparent}.checkbox{position:relative;display:inline-block;padding:7px 7px;cursor:pointer}.checkbox .checkbox-icon:before,.checkbox input:before{border-color:#ddd}.checkbox input:checked+.checkbox-icon:before,.checkbox input:checked:before{background:#387ef5;border-color:#387ef5}.checkbox-light .checkbox-icon:before,.checkbox-light input:before{border-color:#ddd}.checkbox-light input:checked+.checkbox-icon:before,.checkbox-light input:checked:before{background:#ddd;border-color:#ddd}.checkbox-stable .checkbox-icon:before,.checkbox-stable input:before{border-color:#b2b2b2}.checkbox-stable input:checked+.checkbox-icon:before,.checkbox-stable input:checked:before{background:#b2b2b2;border-color:#b2b2b2}.checkbox-positive .checkbox-icon:before,.checkbox-positive input:before{border-color:#387ef5}.checkbox-positive input:checked+.checkbox-icon:before,.checkbox-positive input:checked:before{background:#387ef5;border-color:#387ef5}.checkbox-calm .checkbox-icon:before,.checkbox-calm input:before{border-color:#11c1f3}.checkbox-calm input:checked+.checkbox-icon:before,.checkbox-calm input:checked:before{background:#11c1f3;border-color:#11c1f3}.checkbox-assertive .checkbox-icon:before,.checkbox-assertive input:before{border-color:#ef473a}.checkbox-assertive input:checked+.checkbox-icon:before,.checkbox-assertive input:checked:before{background:#ef473a;border-color:#ef473a}.checkbox-balanced .checkbox-icon:before,.checkbox-balanced input:before{border-color:#33cd5f}.checkbox-balanced input:checked+.checkbox-icon:before,.checkbox-balanced input:checked:before{background:#33cd5f;border-color:#33cd5f}.checkbox-energized .checkbox-icon:before,.checkbox-energized input:before{border-color:#ffc900}.checkbox-energized input:checked+.checkbox-icon:before,.checkbox-energized input:checked:before{background:#ffc900;border-color:#ffc900}.checkbox-royal .checkbox-icon:before,.checkbox-royal input:before{border-color:#886aea}.checkbox-royal input:checked+.checkbox-icon:before,.checkbox-royal input:checked:before{background:#886aea;border-color:#886aea}.checkbox-dark .checkbox-icon:before,.checkbox-dark input:before{border-color:#444}.checkbox-dark input:checked+.checkbox-icon:before,.checkbox-dark input:checked:before{background:#444;border-color:#444}.checkbox input:disabled+.checkbox-icon:before,.checkbox input:disabled:before{border-color:#ddd}.checkbox input:disabled:checked+.checkbox-icon:before,.checkbox input:disabled:checked:before{background:#ddd}.checkbox.checkbox-input-hidden input{display:none!important}.checkbox input,.checkbox-icon{position:relative;width:28px;height:28px;display:block;border:0;background:0 0;cursor:pointer;-webkit-appearance:none}.checkbox input:before,.checkbox-icon:before{display:table;width:100%;height:100%;border-width:1px;border-style:solid;border-radius:28px;background:#fff;content:' ';-webkit-transition:background-color 20ms ease-in-out;transition:background-color 20ms ease-in-out}.checkbox input:checked:before,input:checked+.checkbox-icon:before{border-width:2px}.checkbox input:after,.checkbox-icon:after{-webkit-transition:opacity .05s ease-in-out;transition:opacity .05s ease-in-out;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);position:absolute;top:33%;left:25%;display:table;width:14px;height:6px;border:1px solid #fff;border-top:0;border-right:0;content:' ';opacity:0}.checkbox-square .checkbox-icon:before,.checkbox-square input:before,.platform-android .checkbox-platform .checkbox-icon:before,.platform-android .checkbox-platform input:before{border-radius:2px;width:72%;height:72%;margin-top:14%;margin-left:14%;border-width:2px}.checkbox-square .checkbox-icon:after,.checkbox-square input:after,.platform-android .checkbox-platform .checkbox-icon:after,.platform-android .checkbox-platform input:after{border-width:2px;top:19%;left:25%;width:13px;height:7px}.platform-android .item-checkbox-right .checkbox-square .checkbox-icon::after{top:31%}.grade-c .checkbox input:after,.grade-c .checkbox-icon:after{-webkit-transform:rotate(0);transform:rotate(0);top:3px;left:4px;border:none;color:#fff;content:'\2713';font-weight:700;font-size:20px}.checkbox input:checked:after,input:checked+.checkbox-icon:after{opacity:1}.item-checkbox{padding-left:60px}.item-checkbox.active{box-shadow:none}.item-checkbox .checkbox{position:absolute;top:50%;right:8px;left:8px;z-index:3;margin-top:-21px}.item-checkbox.item-checkbox-right{padding-right:60px;padding-left:16px}.item-checkbox-right .checkbox input,.item-checkbox-right .checkbox-icon{float:right}.item-toggle{pointer-events:none}.toggle{position:relative;display:inline-block;pointer-events:auto;margin:-5px;padding:5px}.toggle input:checked+.track{border-color:#4cd964;background-color:#4cd964}.toggle.dragging .handle{background-color:#f2f2f2!important}.toggle.toggle-light input:checked+.track{border-color:#ddd;background-color:#ddd}.toggle.toggle-stable input:checked+.track{border-color:#b2b2b2;background-color:#b2b2b2}.toggle.toggle-positive input:checked+.track{border-color:#387ef5;background-color:#387ef5}.toggle.toggle-calm input:checked+.track{border-color:#11c1f3;background-color:#11c1f3}.toggle.toggle-assertive input:checked+.track{border-color:#ef473a;background-color:#ef473a}.toggle.toggle-balanced input:checked+.track{border-color:#33cd5f;background-color:#33cd5f}.toggle.toggle-energized input:checked+.track{border-color:#ffc900;background-color:#ffc900}.toggle.toggle-royal input:checked+.track{border-color:#886aea;background-color:#886aea}.toggle.toggle-dark input:checked+.track{border-color:#444;background-color:#444}.toggle input{display:none}.toggle .track{-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transition-property:background-color,border;transition-property:background-color,border;display:inline-block;box-sizing:border-box;width:51px;height:31px;border:solid 2px #e6e6e6;border-radius:20px;background-color:#fff;content:' ';cursor:pointer;pointer-events:none}.platform-android4_2 .toggle .track{-webkit-background-clip:padding-box}.toggle .handle{-webkit-transition:.3s cubic-bezier(0,1.1,1,1.1);transition:.3s cubic-bezier(0,1.1,1,1.1);-webkit-transition-property:background-color,transform;transition-property:background-color,transform;position:absolute;display:block;width:27px;height:27px;border-radius:27px;background-color:#fff;top:7px;left:7px;box-shadow:0 2px 7px rgba(0,0,0,.35),0 1px 1px rgba(0,0,0,.15)}.toggle .handle:before{position:absolute;top:-4px;left:-21.5px;padding:18.5px 34px;content:" "}.toggle input:checked+.track .handle{-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0);background-color:#fff}.item-toggle.active{box-shadow:none}.item-toggle,.item-toggle.item-complex .item-content{padding-right:99px}.item-toggle.item-complex{padding-right:0}.item-toggle .toggle{position:absolute;top:10px;right:16px;z-index:3}.toggle input:disabled+.track{opacity:.6}.toggle-small .track{border:0;width:34px;height:15px;background:#9e9e9e}.toggle-small input:checked+.track{background:rgba(0,150,137,.5)}.toggle-small .handle{top:2px;left:4px;width:21px;height:21px;box-shadow:0 2px 5px rgba(0,0,0,.25)}.toggle-small input:checked+.track .handle{-webkit-transform:translate3d(16px,0,0);transform:translate3d(16px,0,0);background:#009689}.toggle-small.item-toggle .toggle{top:19px}.toggle-small .toggle-light input:checked+.track{background-color:rgba(221,221,221,.5)}.toggle-small .toggle-light input:checked+.track .handle{background-color:#ddd}.toggle-small .toggle-stable input:checked+.track{background-color:rgba(178,178,178,.5)}.toggle-small .toggle-stable input:checked+.track .handle{background-color:#b2b2b2}.toggle-small .toggle-positive input:checked+.track{background-color:rgba(56,126,245,.5)}.toggle-small .toggle-positive input:checked+.track .handle{background-color:#387ef5}.toggle-small .toggle-calm input:checked+.track{background-color:rgba(17,193,243,.5)}.toggle-small .toggle-calm input:checked+.track .handle{background-color:#11c1f3}.toggle-small .toggle-assertive input:checked+.track{background-color:rgba(239,71,58,.5)}.toggle-small .toggle-assertive input:checked+.track .handle{background-color:#ef473a}.toggle-small .toggle-balanced input:checked+.track{background-color:rgba(51,205,95,.5)}.toggle-small .toggle-balanced input:checked+.track .handle{background-color:#33cd5f}.toggle-small .toggle-energized input:checked+.track{background-color:rgba(255,201,0,.5)}.toggle-small .toggle-energized input:checked+.track .handle{background-color:#ffc900}.toggle-small .toggle-royal input:checked+.track{background-color:rgba(136,106,234,.5)}.toggle-small .toggle-royal input:checked+.track .handle{background-color:#886aea}.toggle-small .toggle-dark input:checked+.track{background-color:rgba(68,68,68,.5)}.toggle-small .toggle-dark input:checked+.track .handle{background-color:#444}.item-radio{padding:0}.item-radio:hover{cursor:pointer}.item-radio .item-content{padding-right:64px}.item-radio .radio-icon{position:absolute;top:0;right:0;z-index:3;visibility:hidden;padding:14px;height:100%;font-size:24px}.item-radio input{position:absolute;left:-9999px}.item-radio input:checked+.radio-content .item-content{background:#f7f7f7}.item-radio input:checked+.radio-content .radio-icon{visibility:visible}.range input{overflow:hidden;margin-top:5px;margin-bottom:5px;padding-right:2px;padding-left:1px;width:auto;height:43px;outline:0;background:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#ccc),color-stop(100%,#ccc));background:linear-gradient(to right,#ccc 0,#ccc 100%);background-position:center;background-size:99% 2px;background-repeat:no-repeat;-webkit-appearance:none}.range input::-moz-focus-outer{border:0}.range input::-webkit-slider-thumb{position:relative;width:28px;height:28px;border-radius:50%;background-color:#fff;box-shadow:0 0 2px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2);cursor:pointer;-webkit-appearance:none;border:0}.range input::-webkit-slider-thumb:before{position:absolute;top:13px;left:-2001px;width:2000px;height:2px;background:#444;content:' '}.range input::-webkit-slider-thumb:after{position:absolute;top:-15px;left:-15px;padding:30px;content:' '}.range input::-ms-fill-lower{height:2px;background:#444}.range{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center;padding:2px 11px}.range.range-light input::-webkit-slider-thumb:before{background:#ddd}.range.range-light input::-ms-fill-lower{background:#ddd}.range.range-stable input::-webkit-slider-thumb:before{background:#b2b2b2}.range.range-stable input::-ms-fill-lower{background:#b2b2b2}.range.range-positive input::-webkit-slider-thumb:before{background:#387ef5}.range.range-positive input::-ms-fill-lower{background:#387ef5}.range.range-calm input::-webkit-slider-thumb:before{background:#11c1f3}.range.range-calm input::-ms-fill-lower{background:#11c1f3}.range.range-balanced input::-webkit-slider-thumb:before{background:#33cd5f}.range.range-balanced input::-ms-fill-lower{background:#33cd5f}.range.range-assertive input::-webkit-slider-thumb:before{background:#ef473a}.range.range-assertive input::-ms-fill-lower{background:#ef473a}.range.range-energized input::-webkit-slider-thumb:before{background:#ffc900}.range.range-energized input::-ms-fill-lower{background:#ffc900}.range.range-royal input::-webkit-slider-thumb:before{background:#886aea}.range.range-royal input::-ms-fill-lower{background:#886aea}.range.range-dark input::-webkit-slider-thumb:before{background:#444}.range.range-dark input::-ms-fill-lower{background:#444}.range .icon{-webkit-box-flex:0;-webkit-flex:0;-moz-box-flex:0;-moz-flex:0;-ms-flex:0;flex:0;display:block;min-width:24px;text-align:center;font-size:24px}.range input{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;display:block;margin-right:10px;margin-left:10px}.range-label{-webkit-box-flex:0;-webkit-flex:0 0 auto;-moz-box-flex:0;-moz-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;display:block;white-space:nowrap}.range-label:first-child{padding-left:5px}.range input+.range-label{padding-right:5px;padding-left:0}.platform-windowsphone .range input{height:auto}.item-select{position:relative}.item-select select{-webkit-appearance:none;-moz-appearance:none;appearance:none;position:absolute;top:0;bottom:0;right:0;padding:0 48px 0 16px;max-width:65%;border:none;background:#fff;color:#333;text-indent:.01px;text-overflow:'';white-space:nowrap;font-size:14px;cursor:pointer;direction:rtl}.item-select select::-ms-expand{display:none}.item-select option{direction:ltr}.item-select:after{position:absolute;top:50%;right:16px;margin-top:-3px;width:0;height:0;border-top:5px solid;border-right:5px solid transparent;border-left:5px solid transparent;color:#999;content:"";pointer-events:none}.item-select.item-light select{background:#fff;color:#444}.item-select.item-stable select{background:#f8f8f8;color:#444}.item-select.item-stable .input-label,.item-select.item-stable:after{color:#666}.item-select.item-positive select{background:#387ef5;color:#fff}.item-select.item-positive .input-label,.item-select.item-positive:after{color:#fff}.item-select.item-calm select{background:#11c1f3;color:#fff}.item-select.item-calm .input-label,.item-select.item-calm:after{color:#fff}.item-select.item-assertive select{background:#ef473a;color:#fff}.item-select.item-assertive .input-label,.item-select.item-assertive:after{color:#fff}.item-select.item-balanced select{background:#33cd5f;color:#fff}.item-select.item-balanced .input-label,.item-select.item-balanced:after{color:#fff}.item-select.item-energized select{background:#ffc900;color:#fff}.item-select.item-energized .input-label,.item-select.item-energized:after{color:#fff}.item-select.item-royal select{background:#886aea;color:#fff}.item-select.item-royal .input-label,.item-select.item-royal:after{color:#fff}.item-select.item-dark select{background:#444;color:#fff}.item-select.item-dark .input-label,.item-select.item-dark:after{color:#fff}select[multiple],select[size]{height:auto}progress{display:block;margin:15px auto;width:100%}.button{border-color:transparent;background-color:#f8f8f8;color:#444;position:relative;display:inline-block;margin:0;padding:0 12px;min-width:52px;min-height:47px;border-width:1px;border-style:solid;border-radius:4px;vertical-align:top;text-align:center;text-overflow:ellipsis;font-size:16px;line-height:42px;cursor:pointer}.button:hover{color:#444;text-decoration:none}.button.activated,.button.active{border-color:#a2a2a2;background-color:#e5e5e5}.button:after{position:absolute;top:-6px;right:-6px;bottom:-6px;left:-6px;content:' '}.button .icon{vertical-align:top;pointer-events:none}.button .icon:before,.button.icon-left:before,.button.icon-right:before,.button.icon:before{display:inline-block;padding:0 0 1px 0;vertical-align:inherit;font-size:24px;line-height:41px;pointer-events:none}.button.icon-left:before{float:left;padding-right:.2em;padding-left:0}.button.icon-right:before{float:right;padding-right:0;padding-left:.2em}.button.button-block,.button.button-full{margin-top:10px;margin-bottom:10px}.button.button-light{border-color:transparent;background-color:#fff;color:#444}.button.button-light:hover{color:#444;text-decoration:none}.button.button-light.activated,.button.button-light.active{border-color:#a2a2a2;background-color:#fafafa}.button.button-light.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#ddd}.button.button-light.button-icon{border-color:transparent;background:0 0}.button.button-light.button-outline{border-color:#ddd;background:0 0;color:#ddd}.button.button-light.button-outline.activated,.button.button-light.button-outline.active{background-color:#ddd;box-shadow:none;color:#fff}.button.button-stable{border-color:transparent;background-color:#f8f8f8;color:#444}.button.button-stable:hover{color:#444;text-decoration:none}.button.button-stable.activated,.button.button-stable.active{border-color:#a2a2a2;background-color:#e5e5e5}.button.button-stable.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#b2b2b2}.button.button-stable.button-icon{border-color:transparent;background:0 0}.button.button-stable.button-outline{border-color:#b2b2b2;background:0 0;color:#b2b2b2}.button.button-stable.button-outline.activated,.button.button-stable.button-outline.active{background-color:#b2b2b2;box-shadow:none;color:#fff}.button.button-positive{border-color:transparent;background-color:#387ef5;color:#fff}.button.button-positive:hover{color:#fff;text-decoration:none}.button.button-positive.activated,.button.button-positive.active{border-color:#a2a2a2;background-color:#0c60ee}.button.button-positive.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#387ef5}.button.button-positive.button-icon{border-color:transparent;background:0 0}.button.button-positive.button-outline{border-color:#387ef5;background:0 0;color:#387ef5}.button.button-positive.button-outline.activated,.button.button-positive.button-outline.active{background-color:#387ef5;box-shadow:none;color:#fff}.button.button-calm{border-color:transparent;background-color:#11c1f3;color:#fff}.button.button-calm:hover{color:#fff;text-decoration:none}.button.button-calm.activated,.button.button-calm.active{border-color:#a2a2a2;background-color:#0a9dc7}.button.button-calm.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#11c1f3}.button.button-calm.button-icon{border-color:transparent;background:0 0}.button.button-calm.button-outline{border-color:#11c1f3;background:0 0;color:#11c1f3}.button.button-calm.button-outline.activated,.button.button-calm.button-outline.active{background-color:#11c1f3;box-shadow:none;color:#fff}.button.button-assertive{border-color:transparent;background-color:#ef473a;color:#fff}.button.button-assertive:hover{color:#fff;text-decoration:none}.button.button-assertive.activated,.button.button-assertive.active{border-color:#a2a2a2;background-color:#e42112}.button.button-assertive.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#ef473a}.button.button-assertive.button-icon{border-color:transparent;background:0 0}.button.button-assertive.button-outline{border-color:#ef473a;background:0 0;color:#ef473a}.button.button-assertive.button-outline.activated,.button.button-assertive.button-outline.active{background-color:#ef473a;box-shadow:none;color:#fff}.button.button-balanced{border-color:transparent;background-color:#33cd5f;color:#fff}.button.button-balanced:hover{color:#fff;text-decoration:none}.button.button-balanced.activated,.button.button-balanced.active{border-color:#a2a2a2;background-color:#28a54c}.button.button-balanced.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#33cd5f}.button.button-balanced.button-icon{border-color:transparent;background:0 0}.button.button-balanced.button-outline{border-color:#33cd5f;background:0 0;color:#33cd5f}.button.button-balanced.button-outline.activated,.button.button-balanced.button-outline.active{background-color:#33cd5f;box-shadow:none;color:#fff}.button.button-energized{border-color:transparent;background-color:#ffc900;color:#fff}.button.button-energized:hover{color:#fff;text-decoration:none}.button.button-energized.activated,.button.button-energized.active{border-color:#a2a2a2;background-color:#e6b500}.button.button-energized.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#ffc900}.button.button-energized.button-icon{border-color:transparent;background:0 0}.button.button-energized.button-outline{border-color:#ffc900;background:0 0;color:#ffc900}.button.button-energized.button-outline.activated,.button.button-energized.button-outline.active{background-color:#ffc900;box-shadow:none;color:#fff}.button.button-royal{border-color:transparent;background-color:#886aea;color:#fff}.button.button-royal:hover{color:#fff;text-decoration:none}.button.button-royal.activated,.button.button-royal.active{border-color:#a2a2a2;background-color:#6b46e5}.button.button-royal.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#886aea}.button.button-royal.button-icon{border-color:transparent;background:0 0}.button.button-royal.button-outline{border-color:#886aea;background:0 0;color:#886aea}.button.button-royal.button-outline.activated,.button.button-royal.button-outline.active{background-color:#886aea;box-shadow:none;color:#fff}.button.button-dark{border-color:transparent;background-color:#444;color:#fff}.button.button-dark:hover{color:#fff;text-decoration:none}.button.button-dark.activated,.button.button-dark.active{border-color:#a2a2a2;background-color:#262626}.button.button-dark.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:#444}.button.button-dark.button-icon{border-color:transparent;background:0 0}.button.button-dark.button-outline{border-color:#444;background:0 0;color:#444}.button.button-dark.button-outline.activated,.button.button-dark.button-outline.active{background-color:#444;box-shadow:none;color:#fff}.button-small{padding:2px 4px 1px;min-width:28px;min-height:30px;font-size:12px;line-height:26px}.button-small .icon:before,.button-small.icon-left:before,.button-small.icon-right:before,.button-small.icon:before{font-size:16px;line-height:19px;margin-top:3px}.button-large{padding:0 16px;min-width:68px;min-height:59px;font-size:20px;line-height:53px}.button-large .icon:before,.button-large.icon-left:before,.button-large.icon-right:before,.button-large.icon:before{padding-bottom:2px;font-size:32px;line-height:51px}.button-icon{-webkit-transition:opacity .1s;transition:opacity .1s;padding:0 6px;min-width:initial;border-color:transparent;background:0 0}.button-icon.button.activated,.button-icon.button.active{border-color:transparent;background:0 0;box-shadow:none;opacity:.3}.button-icon .icon:before,.button-icon.icon:before{font-size:32px}.button-clear{-webkit-transition:opacity .1s;transition:opacity .1s;padding:0 6px;max-height:42px;border-color:transparent;background:0 0;box-shadow:none}.button-clear.button-clear{border-color:transparent;background:0 0;box-shadow:none;color:transparent}.button-clear.button-icon{border-color:transparent;background:0 0}.button-clear.activated,.button-clear.active{opacity:.3}.button-outline{-webkit-transition:opacity .1s;transition:opacity .1s;background:0 0;box-shadow:none}.button-outline.button-outline{border-color:transparent;background:0 0;color:transparent}.button-outline.button-outline.activated,.button-outline.button-outline.active{background-color:transparent;box-shadow:none;color:#fff}.padding>.button.button-block:first-child{margin-top:0}.button-block{display:block;clear:both}.button-block:after{clear:both}.button-full,.button-full>.button{display:block;margin-right:0;margin-left:0;border-right-width:0;border-left-width:0;border-radius:0}.button-full>button.button,button.button-block,button.button-full,input.button.button-block{width:100%}a.button{text-decoration:none}a.button .icon:before,a.button.icon-left:before,a.button.icon-right:before,a.button.icon:before{margin-top:2px}.button.disabled,.button[disabled]{opacity:.4;cursor:default!important;pointer-events:none}.button-bar{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;width:100%}.button-bar.button-bar-inline{display:block;width:auto}.button-bar.button-bar-inline:after,.button-bar.button-bar-inline:before{display:table;content:"";line-height:0}.button-bar.button-bar-inline:after{clear:both}.button-bar.button-bar-inline>.button{width:auto;display:inline-block;float:left}.button-bar.bar-light>.button{border-color:#ddd}.button-bar.bar-stable>.button{border-color:#b2b2b2}.button-bar.bar-positive>.button{border-color:#0c60ee}.button-bar.bar-calm>.button{border-color:#0a9dc7}.button-bar.bar-assertive>.button{border-color:#e42112}.button-bar.bar-balanced>.button{border-color:#28a54c}.button-bar.bar-energized>.button{border-color:#e6b500}.button-bar.bar-royal>.button{border-color:#6b46e5}.button-bar.bar-dark>.button{border-color:#111}.button-bar>.button{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;display:block;overflow:hidden;padding:0 16px;width:0;border-width:1px 0 1px 1px;border-radius:0;text-align:center;text-overflow:ellipsis;white-space:nowrap}.button-bar>.button .icon:before,.button-bar>.button:before{line-height:44px}.button-bar>.button:first-child{border-radius:4px 0 0 4px}.button-bar>.button:last-child{border-right-width:1px;border-radius:0 4px 4px 0}.button-bar>.button:only-child{border-radius:4px}.button-bar>.button-small .icon:before,.button-bar>.button-small:before{line-height:28px}.row{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-moz-flex;display:-ms-flexbox;display:flex;padding:5px;width:100%}.row-wrap{-webkit-flex-wrap:wrap;-moz-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.row-no-padding,.row-no-padding>.col{padding:0}.row+.row{margin-top:-5px;padding-top:0}.col{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;display:block;padding:5px;width:100%}.row-top{-webkit-box-align:start;-ms-flex-align:start;-webkit-align-items:flex-start;-moz-align-items:flex-start;align-items:flex-start}.row-bottom{-webkit-box-align:end;-ms-flex-align:end;-webkit-align-items:flex-end;-moz-align-items:flex-end;align-items:flex-end}.row-center{-webkit-box-align:center;-ms-flex-align:center;-webkit-align-items:center;-moz-align-items:center;align-items:center}.row-stretch{-webkit-box-align:stretch;-ms-flex-align:stretch;-webkit-align-items:stretch;-moz-align-items:stretch;align-items:stretch}.row-baseline{-webkit-box-align:baseline;-ms-flex-align:baseline;-webkit-align-items:baseline;-moz-align-items:baseline;align-items:baseline}.col-top{-webkit-align-self:flex-start;-moz-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start}.col-bottom{-webkit-align-self:flex-end;-moz-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end}.col-center{-webkit-align-self:center;-moz-align-self:center;-ms-flex-item-align:center;align-self:center}.col-offset-10{margin-left:10%}.col-offset-20{margin-left:20%}.col-offset-25{margin-left:25%}.col-offset-33,.col-offset-34{margin-left:33.3333%}.col-offset-50{margin-left:50%}.col-offset-66,.col-offset-67{margin-left:66.6666%}.col-offset-75{margin-left:75%}.col-offset-80{margin-left:80%}.col-offset-90{margin-left:90%}.col-10{-webkit-box-flex:0;-webkit-flex:0 0 10%;-moz-box-flex:0;-moz-flex:0 0 10%;-ms-flex:0 0 10%;flex:0 0 10%;max-width:10%}.col-20{-webkit-box-flex:0;-webkit-flex:0 0 20%;-moz-box-flex:0;-moz-flex:0 0 20%;-ms-flex:0 0 20%;flex:0 0 20%;max-width:20%}.col-25{-webkit-box-flex:0;-webkit-flex:0 0 25%;-moz-box-flex:0;-moz-flex:0 0 25%;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-33,.col-34{-webkit-box-flex:0;-webkit-flex:0 0 33.3333%;-moz-box-flex:0;-moz-flex:0 0 33.3333%;-ms-flex:0 0 33.3333%;flex:0 0 33.3333%;max-width:33.3333%}.col-40{-webkit-box-flex:0;-webkit-flex:0 0 40%;-moz-box-flex:0;-moz-flex:0 0 40%;-ms-flex:0 0 40%;flex:0 0 40%;max-width:40%}.col-50{-webkit-box-flex:0;-webkit-flex:0 0 50%;-moz-box-flex:0;-moz-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-60{-webkit-box-flex:0;-webkit-flex:0 0 60%;-moz-box-flex:0;-moz-flex:0 0 60%;-ms-flex:0 0 60%;flex:0 0 60%;max-width:60%}.col-66,.col-67{-webkit-box-flex:0;-webkit-flex:0 0 66.6666%;-moz-box-flex:0;-moz-flex:0 0 66.6666%;-ms-flex:0 0 66.6666%;flex:0 0 66.6666%;max-width:66.6666%}.col-75{-webkit-box-flex:0;-webkit-flex:0 0 75%;-moz-box-flex:0;-moz-flex:0 0 75%;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-80{-webkit-box-flex:0;-webkit-flex:0 0 80%;-moz-box-flex:0;-moz-flex:0 0 80%;-ms-flex:0 0 80%;flex:0 0 80%;max-width:80%}.col-90{-webkit-box-flex:0;-webkit-flex:0 0 90%;-moz-box-flex:0;-moz-flex:0 0 90%;-ms-flex:0 0 90%;flex:0 0 90%;max-width:90%}@media (max-width:567px){.responsive-sm{-webkit-box-direction:normal;-moz-box-direction:normal;-webkit-box-orient:vertical;-moz-box-orient:vertical;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.responsive-sm .col,.responsive-sm .col-10,.responsive-sm .col-20,.responsive-sm .col-25,.responsive-sm .col-33,.responsive-sm .col-34,.responsive-sm .col-50,.responsive-sm .col-66,.responsive-sm .col-67,.responsive-sm .col-75,.responsive-sm .col-80,.responsive-sm .col-90{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;margin-bottom:15px;margin-left:0;max-width:100%;width:100%}}@media (max-width:767px){.responsive-md{-webkit-box-direction:normal;-moz-box-direction:normal;-webkit-box-orient:vertical;-moz-box-orient:vertical;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.responsive-md .col,.responsive-md .col-10,.responsive-md .col-20,.responsive-md .col-25,.responsive-md .col-33,.responsive-md .col-34,.responsive-md .col-50,.responsive-md .col-66,.responsive-md .col-67,.responsive-md .col-75,.responsive-md .col-80,.responsive-md .col-90{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;margin-bottom:15px;margin-left:0;max-width:100%;width:100%}}@media (max-width:1023px){.responsive-lg{-webkit-box-direction:normal;-moz-box-direction:normal;-webkit-box-orient:vertical;-moz-box-orient:vertical;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.responsive-lg .col,.responsive-lg .col-10,.responsive-lg .col-20,.responsive-lg .col-25,.responsive-lg .col-33,.responsive-lg .col-34,.responsive-lg .col-50,.responsive-lg .col-66,.responsive-lg .col-67,.responsive-lg .col-75,.responsive-lg .col-80,.responsive-lg .col-90{-webkit-box-flex:1;-webkit-flex:1;-moz-box-flex:1;-moz-flex:1;-ms-flex:1;flex:1;margin-bottom:15px;margin-left:0;max-width:100%;width:100%}}.hide{display:none}.opacity-hide{opacity:0}.grade-b .opacity-hide,.grade-c .opacity-hide{opacity:1;display:none}.show{display:block}.opacity-show{opacity:1}.invisible{visibility:hidden}.keyboard-open .hide-on-keyboard-open{display:none}.keyboard-open .bar-footer.hide-on-keyboard-open+.pane .has-footer,.keyboard-open .tabs.hide-on-keyboard-open+.pane .has-tabs{bottom:0}.inline{display:inline-block}.disable-pointer-events{pointer-events:none}.enable-pointer-events{pointer-events:auto}.disable-user-behavior{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent;-webkit-tap-highlight-color:transparent;-webkit-user-drag:none;-ms-touch-action:none;-ms-content-zooming:none}.click-block{position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;z-index:99999;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);overflow:hidden}.click-block-hide{-webkit-transform:translate3d(-9999px,0,0);transform:translate3d(-9999px,0,0)}.no-resize{resize:none}.block{display:block;clear:both}.block:after{display:block;visibility:hidden;clear:both;height:0;content:"."}.full-image{width:100%}.clearfix:after,.clearfix:before{display:table;content:"";line-height:0}.clearfix:after{clear:both}.padding{padding:10px}.padding-top,.padding-vertical{padding-top:10px}.padding-horizontal,.padding-right{padding-right:10px}.padding-bottom,.padding-vertical{padding-bottom:10px}.padding-horizontal,.padding-left{padding-left:10px}.iframe-wrapper{position:fixed;-webkit-overflow-scrolling:touch;overflow:scroll}.iframe-wrapper iframe{height:100%;width:100%}.rounded{border-radius:4px}.light,a.light{color:#fff}.light-bg{background-color:#fff}.light-border{border-color:#ddd}.stable,a.stable{color:#f8f8f8}.stable-bg{background-color:#f8f8f8}.stable-border{border-color:#b2b2b2}.positive,a.positive{color:#387ef5}.positive-bg{background-color:#387ef5}.positive-border{border-color:#0c60ee}.calm,a.calm{color:#11c1f3}.calm-bg{background-color:#11c1f3}.calm-border{border-color:#0a9dc7}.assertive,a.assertive{color:#ef473a}.assertive-bg{background-color:#ef473a}.assertive-border{border-color:#e42112}.balanced,a.balanced{color:#33cd5f}.balanced-bg{background-color:#33cd5f}.balanced-border{border-color:#28a54c}.energized,a.energized{color:#ffc900}.energized-bg{background-color:#ffc900}.energized-border{border-color:#e6b500}.royal,a.royal{color:#886aea}.royal-bg{background-color:#886aea}.royal-border{border-color:#6b46e5}.dark,a.dark{color:#444}.dark-bg{background-color:#444}.dark-border{border-color:#111}[collection-repeat]{left:0!important;top:0!important;position:absolute!important;z-index:1}.collection-repeat-container{position:relative;z-index:1}.collection-repeat-after-container{z-index:0;display:block}.collection-repeat-after-container.horizontal{display:inline-block}.ng-cloak,.ng-hide:not(.ng-hide-animate),.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader){height:64px}.platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader).item-input-inset .item-input-wrapper{margin-top:19px!important}.platform-ios.platform-cordova:not(.fullscreen) .bar-header:not(.bar-subheader)>*{margin-top:20px}.platform-ios.platform-cordova:not(.fullscreen) .bar-subheader,.platform-ios.platform-cordova:not(.fullscreen) .has-header,.platform-ios.platform-cordova:not(.fullscreen) .tabs-top>.tabs,.platform-ios.platform-cordova:not(.fullscreen) .tabs.tabs-top{top:64px}.platform-ios.platform-cordova:not(.fullscreen) .has-subheader{top:108px}.platform-ios.platform-cordova:not(.fullscreen) .has-header.has-tabs-top{top:113px}.platform-ios.platform-cordova:not(.fullscreen) .has-header.has-subheader.has-tabs-top{top:157px}.platform-ios.platform-cordova .popover .bar-header:not(.bar-subheader){height:44px}.platform-ios.platform-cordova .popover .bar-header:not(.bar-subheader).item-input-inset .item-input-wrapper{margin-top:-1px}.platform-ios.platform-cordova .popover .bar-header:not(.bar-subheader)>*{margin-top:0}.platform-ios.platform-cordova .popover .bar-subheader,.platform-ios.platform-cordova .popover .has-header{top:44px}.platform-ios.platform-cordova .popover .has-subheader{top:88px}.platform-ios.platform-cordova.status-bar-hide{margin-bottom:20px}@media (orientation:landscape){.platform-ios.platform-browser.platform-ipad{position:fixed}}.platform-c:not(.enable-transitions) *{-webkit-transition:none!important;transition:none!important}.slide-in-up{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}.slide-in-up.ng-enter,.slide-in-up>.ng-enter{-webkit-transition:all cubic-bezier(.1,.7,.1,1) 400ms;transition:all cubic-bezier(.1,.7,.1,1) 400ms}.slide-in-up.ng-enter-active,.slide-in-up>.ng-enter-active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.slide-in-up.ng-leave,.slide-in-up>.ng-leave{-webkit-transition:all ease-in-out 250ms;transition:all ease-in-out 250ms}@-webkit-keyframes scaleOut{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.8);opacity:0}}@keyframes scaleOut{from{transform:scale(1);opacity:1}to{transform:scale(.8);opacity:0}}@-webkit-keyframes superScaleIn{from{-webkit-transform:scale(1.2);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@keyframes superScaleIn{from{transform:scale(1.2);opacity:0}to{transform:scale(1);opacity:1}}[nav-view-transition=ios] [nav-view=entering],[nav-view-transition=ios] [nav-view=leaving]{-webkit-transition-duration:500ms;transition-duration:500ms;-webkit-transition-timing-function:cubic-bezier(.36,.66,.04,1);transition-timing-function:cubic-bezier(.36,.66,.04,1);-webkit-transition-property:opacity,-webkit-transform,box-shadow;transition-property:opacity,transform,box-shadow}[nav-view-transition=ios][nav-view-direction=forward],[nav-view-transition=ios][nav-view-direction=back]{background-color:#000}[nav-view-transition=ios] [nav-view=active],[nav-view-transition=ios][nav-view-direction=forward] [nav-view=entering],[nav-view-transition=ios][nav-view-direction=back] [nav-view=leaving]{z-index:3}[nav-view-transition=ios][nav-view-direction=forward] [nav-view=leaving],[nav-view-transition=ios][nav-view-direction=back] [nav-view=entering]{z-index:2}[nav-bar-transition=ios] .back-text,[nav-bar-transition=ios] .buttons,[nav-bar-transition=ios] .title{-webkit-transition-duration:500ms;transition-duration:500ms;-webkit-transition-timing-function:cubic-bezier(.36,.66,.04,1);transition-timing-function:cubic-bezier(.36,.66,.04,1);-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,transform}[nav-bar-transition=ios] [nav-bar=entering],[nav-bar-transition=ios] [nav-bar=active]{z-index:10}[nav-bar-transition=ios] [nav-bar=entering] .bar,[nav-bar-transition=ios] [nav-bar=active] .bar{background:0 0}[nav-bar-transition=ios] [nav-bar=cached]{display:block}[nav-bar-transition=ios] [nav-bar=cached] .header-item{display:none}[nav-view-transition=android] [nav-view=entering],[nav-view-transition=android] [nav-view=leaving]{-webkit-transition-duration:200ms;transition-duration:200ms;-webkit-transition-timing-function:cubic-bezier(.4,.6,.2,1);transition-timing-function:cubic-bezier(.4,.6,.2,1);-webkit-transition-property:-webkit-transform;transition-property:transform}[nav-view-transition=android] [nav-view=active],[nav-view-transition=android][nav-view-direction=forward] [nav-view=entering],[nav-view-transition=android][nav-view-direction=back] [nav-view=leaving]{z-index:3}[nav-view-transition=android][nav-view-direction=forward] [nav-view=leaving],[nav-view-transition=android][nav-view-direction=back] [nav-view=entering]{z-index:2}[nav-bar-transition=android] .buttons,[nav-bar-transition=android] .title{-webkit-transition-duration:200ms;transition-duration:200ms;-webkit-transition-timing-function:cubic-bezier(.4,.6,.2,1);transition-timing-function:cubic-bezier(.4,.6,.2,1);-webkit-transition-property:opacity;transition-property:opacity}[nav-bar-transition=android] [nav-bar=entering],[nav-bar-transition=android] [nav-bar=active]{z-index:10}[nav-bar-transition=android] [nav-bar=entering] .bar,[nav-bar-transition=android] [nav-bar=active] .bar{background:0 0}[nav-bar-transition=android] [nav-bar=cached]{display:block}[nav-bar-transition=android] [nav-bar=cached] .header-item{display:none}[nav-swipe=fast] .back-text,[nav-swipe=fast] .buttons,[nav-swipe=fast] .title,[nav-swipe=fast] [nav-view]{-webkit-transition-duration:50ms;transition-duration:50ms;-webkit-transition-timing-function:linear;transition-timing-function:linear}[nav-swipe=slow] .back-text,[nav-swipe=slow] .buttons,[nav-swipe=slow] .title,[nav-swipe=slow] [nav-view]{-webkit-transition-duration:160ms;transition-duration:160ms;-webkit-transition-timing-function:linear;transition-timing-function:linear}[nav-bar=cached],[nav-view=cached]{display:none}[nav-view=stage]{opacity:0;-webkit-transition-duration:0;transition-duration:0}[nav-bar=stage] .back-text,[nav-bar=stage] .buttons,[nav-bar=stage] .title{position:absolute;opacity:0;-webkit-transition-duration:0s;transition-duration:0s} \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/css/ui-components.css b/browser-extensions/chrome/copay-chrome-extension/css/ui-components.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.eot b/browser-extensions/chrome/copay-chrome-extension/font/icomoon.eot deleted file mode 100755 index 0db1c59a2..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.eot and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.svg b/browser-extensions/chrome/copay-chrome-extension/font/icomoon.svg deleted file mode 100755 index 636182c7f..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.svg +++ /dev/null @@ -1,91 +0,0 @@ - - - -Generated by IcoMoon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.ttf b/browser-extensions/chrome/copay-chrome-extension/font/icomoon.ttf deleted file mode 100755 index 9b1fd6efb..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.ttf and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.woff b/browser-extensions/chrome/copay-chrome-extension/font/icomoon.woff deleted file mode 100755 index 4e3af2d2a..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/font/icomoon.woff and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.eot b/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.eot deleted file mode 100644 index 92a3f20a3..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.eot and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.svg b/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.svg deleted file mode 100644 index 49fc8f367..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.svg +++ /dev/null @@ -1,2230 +0,0 @@ - - - - - -Created by FontForge 20120731 at Thu Dec 4 09:51:48 2014 - By Adam Bradley -Created by Adam Bradley with FontForge 2.0 (http://fontforge.sf.net) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.ttf b/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.ttf deleted file mode 100644 index c4e463248..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.ttf and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.woff b/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.woff deleted file mode 100644 index 5f3a14e0a..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/fonts/ionicons.woff and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.css b/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.css deleted file mode 100644 index d866a7335..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.css +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Foundation Icons v 3.0 - * Made by ZURB 2013 http://zurb.com/playground/foundation-icon-fonts-3 - * MIT License - */ - -@font-face { - font-family: "foundation-icons"; - src: url("foundation-icons.eot"); - src: url("foundation-icons.eot?#iefix") format("embedded-opentype"), - url("foundation-icons.woff") format("woff"), - url("foundation-icons.ttf") format("truetype"), - url("foundation-icons.svg#fontcustom") format("svg"); - font-weight: normal; - font-style: normal; -} - -.fi-address-book:before, -.fi-alert:before, -.fi-align-center:before, -.fi-align-justify:before, -.fi-align-left:before, -.fi-align-right:before, -.fi-anchor:before, -.fi-annotate:before, -.fi-archive:before, -.fi-arrow-down:before, -.fi-arrow-left:before, -.fi-arrow-right:before, -.fi-arrow-up:before, -.fi-arrows-compress:before, -.fi-arrows-expand:before, -.fi-arrows-in:before, -.fi-arrows-out:before, -.fi-asl:before, -.fi-asterisk:before, -.fi-at-sign:before, -.fi-background-color:before, -.fi-battery-empty:before, -.fi-battery-full:before, -.fi-battery-half:before, -.fi-bitcoin-circle:before, -.fi-bitcoin:before, -.fi-blind:before, -.fi-bluetooth:before, -.fi-bold:before, -.fi-book-bookmark:before, -.fi-book:before, -.fi-bookmark:before, -.fi-braille:before, -.fi-burst-new:before, -.fi-burst-sale:before, -.fi-burst:before, -.fi-calendar:before, -.fi-camera:before, -.fi-check:before, -.fi-checkbox:before, -.fi-clipboard-notes:before, -.fi-clipboard-pencil:before, -.fi-clipboard:before, -.fi-clock:before, -.fi-closed-caption:before, -.fi-cloud:before, -.fi-comment-minus:before, -.fi-comment-quotes:before, -.fi-comment-video:before, -.fi-comment:before, -.fi-comments:before, -.fi-compass:before, -.fi-contrast:before, -.fi-credit-card:before, -.fi-crop:before, -.fi-crown:before, -.fi-css3:before, -.fi-database:before, -.fi-die-five:before, -.fi-die-four:before, -.fi-die-one:before, -.fi-die-six:before, -.fi-die-three:before, -.fi-die-two:before, -.fi-dislike:before, -.fi-dollar-bill:before, -.fi-dollar:before, -.fi-download:before, -.fi-eject:before, -.fi-elevator:before, -.fi-euro:before, -.fi-eye:before, -.fi-fast-forward:before, -.fi-female-symbol:before, -.fi-female:before, -.fi-filter:before, -.fi-first-aid:before, -.fi-flag:before, -.fi-folder-add:before, -.fi-folder-lock:before, -.fi-folder:before, -.fi-foot:before, -.fi-foundation:before, -.fi-graph-bar:before, -.fi-graph-horizontal:before, -.fi-graph-pie:before, -.fi-graph-trend:before, -.fi-guide-dog:before, -.fi-hearing-aid:before, -.fi-heart:before, -.fi-home:before, -.fi-html5:before, -.fi-indent-less:before, -.fi-indent-more:before, -.fi-info:before, -.fi-italic:before, -.fi-key:before, -.fi-laptop:before, -.fi-layout:before, -.fi-lightbulb:before, -.fi-like:before, -.fi-link:before, -.fi-list-bullet:before, -.fi-list-number:before, -.fi-list-thumbnails:before, -.fi-list:before, -.fi-lock:before, -.fi-loop:before, -.fi-magnifying-glass:before, -.fi-mail:before, -.fi-male-female:before, -.fi-male-symbol:before, -.fi-male:before, -.fi-map:before, -.fi-marker:before, -.fi-megaphone:before, -.fi-microphone:before, -.fi-minus-circle:before, -.fi-minus:before, -.fi-mobile-signal:before, -.fi-mobile:before, -.fi-monitor:before, -.fi-mountains:before, -.fi-music:before, -.fi-next:before, -.fi-no-dogs:before, -.fi-no-smoking:before, -.fi-page-add:before, -.fi-page-copy:before, -.fi-page-csv:before, -.fi-page-delete:before, -.fi-page-doc:before, -.fi-page-edit:before, -.fi-page-export-csv:before, -.fi-page-export-doc:before, -.fi-page-export-pdf:before, -.fi-page-export:before, -.fi-page-filled:before, -.fi-page-multiple:before, -.fi-page-pdf:before, -.fi-page-remove:before, -.fi-page-search:before, -.fi-page:before, -.fi-paint-bucket:before, -.fi-paperclip:before, -.fi-pause:before, -.fi-paw:before, -.fi-paypal:before, -.fi-pencil:before, -.fi-photo:before, -.fi-play-circle:before, -.fi-play-video:before, -.fi-play:before, -.fi-plus:before, -.fi-pound:before, -.fi-power:before, -.fi-previous:before, -.fi-price-tag:before, -.fi-pricetag-multiple:before, -.fi-print:before, -.fi-prohibited:before, -.fi-projection-screen:before, -.fi-puzzle:before, -.fi-quote:before, -.fi-record:before, -.fi-refresh:before, -.fi-results-demographics:before, -.fi-results:before, -.fi-rewind-ten:before, -.fi-rewind:before, -.fi-rss:before, -.fi-safety-cone:before, -.fi-save:before, -.fi-share:before, -.fi-sheriff-badge:before, -.fi-shield:before, -.fi-shopping-bag:before, -.fi-shopping-cart:before, -.fi-shuffle:before, -.fi-skull:before, -.fi-social-500px:before, -.fi-social-adobe:before, -.fi-social-amazon:before, -.fi-social-android:before, -.fi-social-apple:before, -.fi-social-behance:before, -.fi-social-bing:before, -.fi-social-blogger:before, -.fi-social-delicious:before, -.fi-social-designer-news:before, -.fi-social-deviant-art:before, -.fi-social-digg:before, -.fi-social-dribbble:before, -.fi-social-drive:before, -.fi-social-dropbox:before, -.fi-social-evernote:before, -.fi-social-facebook:before, -.fi-social-flickr:before, -.fi-social-forrst:before, -.fi-social-foursquare:before, -.fi-social-game-center:before, -.fi-social-github:before, -.fi-social-google-plus:before, -.fi-social-hacker-news:before, -.fi-social-hi5:before, -.fi-social-instagram:before, -.fi-social-joomla:before, -.fi-social-lastfm:before, -.fi-social-linkedin:before, -.fi-social-medium:before, -.fi-social-myspace:before, -.fi-social-orkut:before, -.fi-social-path:before, -.fi-social-picasa:before, -.fi-social-pinterest:before, -.fi-social-rdio:before, -.fi-social-reddit:before, -.fi-social-skillshare:before, -.fi-social-skype:before, -.fi-social-smashing-mag:before, -.fi-social-snapchat:before, -.fi-social-spotify:before, -.fi-social-squidoo:before, -.fi-social-stack-overflow:before, -.fi-social-steam:before, -.fi-social-stumbleupon:before, -.fi-social-treehouse:before, -.fi-social-tumblr:before, -.fi-social-twitter:before, -.fi-social-vimeo:before, -.fi-social-windows:before, -.fi-social-xbox:before, -.fi-social-yahoo:before, -.fi-social-yelp:before, -.fi-social-youtube:before, -.fi-social-zerply:before, -.fi-social-zurb:before, -.fi-sound:before, -.fi-star:before, -.fi-stop:before, -.fi-strikethrough:before, -.fi-subscript:before, -.fi-superscript:before, -.fi-tablet-landscape:before, -.fi-tablet-portrait:before, -.fi-target-two:before, -.fi-target:before, -.fi-telephone-accessible:before, -.fi-telephone:before, -.fi-text-color:before, -.fi-thumbnails:before, -.fi-ticket:before, -.fi-torso-business:before, -.fi-torso-female:before, -.fi-torso:before, -.fi-torsos-all-female:before, -.fi-torsos-all:before, -.fi-torsos-female-male:before, -.fi-torsos-male-female:before, -.fi-torsos:before, -.fi-trash:before, -.fi-trees:before, -.fi-trophy:before, -.fi-underline:before, -.fi-universal-access:before, -.fi-unlink:before, -.fi-unlock:before, -.fi-upload-cloud:before, -.fi-upload:before, -.fi-usb:before, -.fi-video:before, -.fi-volume-none:before, -.fi-volume-strike:before, -.fi-volume:before, -.fi-web:before, -.fi-wheelchair:before, -.fi-widget:before, -.fi-wrench:before, -.fi-x-circle:before, -.fi-x:before, -.fi-yen:before, -.fi-zoom-in:before, -.fi-zoom-out:before { - font-family: "foundation-icons"; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - -webkit-font-smoothing: antialiased; - display: inline-block; - text-decoration: inherit; -} - -.fi-address-book:before { content: "\f100"; } -.fi-alert:before { content: "\f101"; } -.fi-align-center:before { content: "\f102"; } -.fi-align-justify:before { content: "\f103"; } -.fi-align-left:before { content: "\f104"; } -.fi-align-right:before { content: "\f105"; } -.fi-anchor:before { content: "\f106"; } -.fi-annotate:before { content: "\f107"; } -.fi-archive:before { content: "\f108"; } -.fi-arrow-down:before { content: "\f109"; } -.fi-arrow-left:before { content: "\f10a"; } -.fi-arrow-right:before { content: "\f10b"; } -.fi-arrow-up:before { content: "\f10c"; } -.fi-arrows-compress:before { content: "\f10d"; } -.fi-arrows-expand:before { content: "\f10e"; } -.fi-arrows-in:before { content: "\f10f"; } -.fi-arrows-out:before { content: "\f110"; } -.fi-asl:before { content: "\f111"; } -.fi-asterisk:before { content: "\f112"; } -.fi-at-sign:before { content: "\f113"; } -.fi-background-color:before { content: "\f114"; } -.fi-battery-empty:before { content: "\f115"; } -.fi-battery-full:before { content: "\f116"; } -.fi-battery-half:before { content: "\f117"; } -.fi-bitcoin-circle:before { content: "\f118"; } -.fi-bitcoin:before { content: "\f119"; } -.fi-blind:before { content: "\f11a"; } -.fi-bluetooth:before { content: "\f11b"; } -.fi-bold:before { content: "\f11c"; } -.fi-book-bookmark:before { content: "\f11d"; } -.fi-book:before { content: "\f11e"; } -.fi-bookmark:before { content: "\f11f"; } -.fi-braille:before { content: "\f120"; } -.fi-burst-new:before { content: "\f121"; } -.fi-burst-sale:before { content: "\f122"; } -.fi-burst:before { content: "\f123"; } -.fi-calendar:before { content: "\f124"; } -.fi-camera:before { content: "\f125"; } -.fi-check:before { content: "\f126"; } -.fi-checkbox:before { content: "\f127"; } -.fi-clipboard-notes:before { content: "\f128"; } -.fi-clipboard-pencil:before { content: "\f129"; } -.fi-clipboard:before { content: "\f12a"; } -.fi-clock:before { content: "\f12b"; } -.fi-closed-caption:before { content: "\f12c"; } -.fi-cloud:before { content: "\f12d"; } -.fi-comment-minus:before { content: "\f12e"; } -.fi-comment-quotes:before { content: "\f12f"; } -.fi-comment-video:before { content: "\f130"; } -.fi-comment:before { content: "\f131"; } -.fi-comments:before { content: "\f132"; } -.fi-compass:before { content: "\f133"; } -.fi-contrast:before { content: "\f134"; } -.fi-credit-card:before { content: "\f135"; } -.fi-crop:before { content: "\f136"; } -.fi-crown:before { content: "\f137"; } -.fi-css3:before { content: "\f138"; } -.fi-database:before { content: "\f139"; } -.fi-die-five:before { content: "\f13a"; } -.fi-die-four:before { content: "\f13b"; } -.fi-die-one:before { content: "\f13c"; } -.fi-die-six:before { content: "\f13d"; } -.fi-die-three:before { content: "\f13e"; } -.fi-die-two:before { content: "\f13f"; } -.fi-dislike:before { content: "\f140"; } -.fi-dollar-bill:before { content: "\f141"; } -.fi-dollar:before { content: "\f142"; } -.fi-download:before { content: "\f143"; } -.fi-eject:before { content: "\f144"; } -.fi-elevator:before { content: "\f145"; } -.fi-euro:before { content: "\f146"; } -.fi-eye:before { content: "\f147"; } -.fi-fast-forward:before { content: "\f148"; } -.fi-female-symbol:before { content: "\f149"; } -.fi-female:before { content: "\f14a"; } -.fi-filter:before { content: "\f14b"; } -.fi-first-aid:before { content: "\f14c"; } -.fi-flag:before { content: "\f14d"; } -.fi-folder-add:before { content: "\f14e"; } -.fi-folder-lock:before { content: "\f14f"; } -.fi-folder:before { content: "\f150"; } -.fi-foot:before { content: "\f151"; } -.fi-foundation:before { content: "\f152"; } -.fi-graph-bar:before { content: "\f153"; } -.fi-graph-horizontal:before { content: "\f154"; } -.fi-graph-pie:before { content: "\f155"; } -.fi-graph-trend:before { content: "\f156"; } -.fi-guide-dog:before { content: "\f157"; } -.fi-hearing-aid:before { content: "\f158"; } -.fi-heart:before { content: "\f159"; } -.fi-home:before { content: "\f15a"; } -.fi-html5:before { content: "\f15b"; } -.fi-indent-less:before { content: "\f15c"; } -.fi-indent-more:before { content: "\f15d"; } -.fi-info:before { content: "\f15e"; } -.fi-italic:before { content: "\f15f"; } -.fi-key:before { content: "\f160"; } -.fi-laptop:before { content: "\f161"; } -.fi-layout:before { content: "\f162"; } -.fi-lightbulb:before { content: "\f163"; } -.fi-like:before { content: "\f164"; } -.fi-link:before { content: "\f165"; } -.fi-list-bullet:before { content: "\f166"; } -.fi-list-number:before { content: "\f167"; } -.fi-list-thumbnails:before { content: "\f168"; } -.fi-list:before { content: "\f169"; } -.fi-lock:before { content: "\f16a"; } -.fi-loop:before { content: "\f16b"; } -.fi-magnifying-glass:before { content: "\f16c"; } -.fi-mail:before { content: "\f16d"; } -.fi-male-female:before { content: "\f16e"; } -.fi-male-symbol:before { content: "\f16f"; } -.fi-male:before { content: "\f170"; } -.fi-map:before { content: "\f171"; } -.fi-marker:before { content: "\f172"; } -.fi-megaphone:before { content: "\f173"; } -.fi-microphone:before { content: "\f174"; } -.fi-minus-circle:before { content: "\f175"; } -.fi-minus:before { content: "\f176"; } -.fi-mobile-signal:before { content: "\f177"; } -.fi-mobile:before { content: "\f178"; } -.fi-monitor:before { content: "\f179"; } -.fi-mountains:before { content: "\f17a"; } -.fi-music:before { content: "\f17b"; } -.fi-next:before { content: "\f17c"; } -.fi-no-dogs:before { content: "\f17d"; } -.fi-no-smoking:before { content: "\f17e"; } -.fi-page-add:before { content: "\f17f"; } -.fi-page-copy:before { content: "\f180"; } -.fi-page-csv:before { content: "\f181"; } -.fi-page-delete:before { content: "\f182"; } -.fi-page-doc:before { content: "\f183"; } -.fi-page-edit:before { content: "\f184"; } -.fi-page-export-csv:before { content: "\f185"; } -.fi-page-export-doc:before { content: "\f186"; } -.fi-page-export-pdf:before { content: "\f187"; } -.fi-page-export:before { content: "\f188"; } -.fi-page-filled:before { content: "\f189"; } -.fi-page-multiple:before { content: "\f18a"; } -.fi-page-pdf:before { content: "\f18b"; } -.fi-page-remove:before { content: "\f18c"; } -.fi-page-search:before { content: "\f18d"; } -.fi-page:before { content: "\f18e"; } -.fi-paint-bucket:before { content: "\f18f"; } -.fi-paperclip:before { content: "\f190"; } -.fi-pause:before { content: "\f191"; } -.fi-paw:before { content: "\f192"; } -.fi-paypal:before { content: "\f193"; } -.fi-pencil:before { content: "\f194"; } -.fi-photo:before { content: "\f195"; } -.fi-play-circle:before { content: "\f196"; } -.fi-play-video:before { content: "\f197"; } -.fi-play:before { content: "\f198"; } -.fi-plus:before { content: "\f199"; } -.fi-pound:before { content: "\f19a"; } -.fi-power:before { content: "\f19b"; } -.fi-previous:before { content: "\f19c"; } -.fi-price-tag:before { content: "\f19d"; } -.fi-pricetag-multiple:before { content: "\f19e"; } -.fi-print:before { content: "\f19f"; } -.fi-prohibited:before { content: "\f1a0"; } -.fi-projection-screen:before { content: "\f1a1"; } -.fi-puzzle:before { content: "\f1a2"; } -.fi-quote:before { content: "\f1a3"; } -.fi-record:before { content: "\f1a4"; } -.fi-refresh:before { content: "\f1a5"; } -.fi-results-demographics:before { content: "\f1a6"; } -.fi-results:before { content: "\f1a7"; } -.fi-rewind-ten:before { content: "\f1a8"; } -.fi-rewind:before { content: "\f1a9"; } -.fi-rss:before { content: "\f1aa"; } -.fi-safety-cone:before { content: "\f1ab"; } -.fi-save:before { content: "\f1ac"; } -.fi-share:before { content: "\f1ad"; } -.fi-sheriff-badge:before { content: "\f1ae"; } -.fi-shield:before { content: "\f1af"; } -.fi-shopping-bag:before { content: "\f1b0"; } -.fi-shopping-cart:before { content: "\f1b1"; } -.fi-shuffle:before { content: "\f1b2"; } -.fi-skull:before { content: "\f1b3"; } -.fi-social-500px:before { content: "\f1b4"; } -.fi-social-adobe:before { content: "\f1b5"; } -.fi-social-amazon:before { content: "\f1b6"; } -.fi-social-android:before { content: "\f1b7"; } -.fi-social-apple:before { content: "\f1b8"; } -.fi-social-behance:before { content: "\f1b9"; } -.fi-social-bing:before { content: "\f1ba"; } -.fi-social-blogger:before { content: "\f1bb"; } -.fi-social-delicious:before { content: "\f1bc"; } -.fi-social-designer-news:before { content: "\f1bd"; } -.fi-social-deviant-art:before { content: "\f1be"; } -.fi-social-digg:before { content: "\f1bf"; } -.fi-social-dribbble:before { content: "\f1c0"; } -.fi-social-drive:before { content: "\f1c1"; } -.fi-social-dropbox:before { content: "\f1c2"; } -.fi-social-evernote:before { content: "\f1c3"; } -.fi-social-facebook:before { content: "\f1c4"; } -.fi-social-flickr:before { content: "\f1c5"; } -.fi-social-forrst:before { content: "\f1c6"; } -.fi-social-foursquare:before { content: "\f1c7"; } -.fi-social-game-center:before { content: "\f1c8"; } -.fi-social-github:before { content: "\f1c9"; } -.fi-social-google-plus:before { content: "\f1ca"; } -.fi-social-hacker-news:before { content: "\f1cb"; } -.fi-social-hi5:before { content: "\f1cc"; } -.fi-social-instagram:before { content: "\f1cd"; } -.fi-social-joomla:before { content: "\f1ce"; } -.fi-social-lastfm:before { content: "\f1cf"; } -.fi-social-linkedin:before { content: "\f1d0"; } -.fi-social-medium:before { content: "\f1d1"; } -.fi-social-myspace:before { content: "\f1d2"; } -.fi-social-orkut:before { content: "\f1d3"; } -.fi-social-path:before { content: "\f1d4"; } -.fi-social-picasa:before { content: "\f1d5"; } -.fi-social-pinterest:before { content: "\f1d6"; } -.fi-social-rdio:before { content: "\f1d7"; } -.fi-social-reddit:before { content: "\f1d8"; } -.fi-social-skillshare:before { content: "\f1d9"; } -.fi-social-skype:before { content: "\f1da"; } -.fi-social-smashing-mag:before { content: "\f1db"; } -.fi-social-snapchat:before { content: "\f1dc"; } -.fi-social-spotify:before { content: "\f1dd"; } -.fi-social-squidoo:before { content: "\f1de"; } -.fi-social-stack-overflow:before { content: "\f1df"; } -.fi-social-steam:before { content: "\f1e0"; } -.fi-social-stumbleupon:before { content: "\f1e1"; } -.fi-social-treehouse:before { content: "\f1e2"; } -.fi-social-tumblr:before { content: "\f1e3"; } -.fi-social-twitter:before { content: "\f1e4"; } -.fi-social-vimeo:before { content: "\f1e5"; } -.fi-social-windows:before { content: "\f1e6"; } -.fi-social-xbox:before { content: "\f1e7"; } -.fi-social-yahoo:before { content: "\f1e8"; } -.fi-social-yelp:before { content: "\f1e9"; } -.fi-social-youtube:before { content: "\f1ea"; } -.fi-social-zerply:before { content: "\f1eb"; } -.fi-social-zurb:before { content: "\f1ec"; } -.fi-sound:before { content: "\f1ed"; } -.fi-star:before { content: "\f1ee"; } -.fi-stop:before { content: "\f1ef"; } -.fi-strikethrough:before { content: "\f1f0"; } -.fi-subscript:before { content: "\f1f1"; } -.fi-superscript:before { content: "\f1f2"; } -.fi-tablet-landscape:before { content: "\f1f3"; } -.fi-tablet-portrait:before { content: "\f1f4"; } -.fi-target-two:before { content: "\f1f5"; } -.fi-target:before { content: "\f1f6"; } -.fi-telephone-accessible:before { content: "\f1f7"; } -.fi-telephone:before { content: "\f1f8"; } -.fi-text-color:before { content: "\f1f9"; } -.fi-thumbnails:before { content: "\f1fa"; } -.fi-ticket:before { content: "\f1fb"; } -.fi-torso-business:before { content: "\f1fc"; } -.fi-torso-female:before { content: "\f1fd"; } -.fi-torso:before { content: "\f1fe"; } -.fi-torsos-all-female:before { content: "\f1ff"; } -.fi-torsos-all:before { content: "\f200"; } -.fi-torsos-female-male:before { content: "\f201"; } -.fi-torsos-male-female:before { content: "\f202"; } -.fi-torsos:before { content: "\f203"; } -.fi-trash:before { content: "\f204"; } -.fi-trees:before { content: "\f205"; } -.fi-trophy:before { content: "\f206"; } -.fi-underline:before { content: "\f207"; } -.fi-universal-access:before { content: "\f208"; } -.fi-unlink:before { content: "\f209"; } -.fi-unlock:before { content: "\f20a"; } -.fi-upload-cloud:before { content: "\f20b"; } -.fi-upload:before { content: "\f20c"; } -.fi-usb:before { content: "\f20d"; } -.fi-video:before { content: "\f20e"; } -.fi-volume-none:before { content: "\f20f"; } -.fi-volume-strike:before { content: "\f210"; } -.fi-volume:before { content: "\f211"; } -.fi-web:before { content: "\f212"; } -.fi-wheelchair:before { content: "\f213"; } -.fi-widget:before { content: "\f214"; } -.fi-wrench:before { content: "\f215"; } -.fi-x-circle:before { content: "\f216"; } -.fi-x:before { content: "\f217"; } -.fi-yen:before { content: "\f218"; } -.fi-zoom-in:before { content: "\f219"; } -.fi-zoom-out:before { content: "\f21a"; } diff --git a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.eot b/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.eot deleted file mode 100644 index 1746ad407..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.eot and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.svg b/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.svg deleted file mode 100644 index 4e014ff89..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.svg +++ /dev/null @@ -1,970 +0,0 @@ - - - - - -Created by FontForge 20120731 at Fri Aug 23 09:25:55 2013 - By Jordan Humphreys -Created by Jordan Humphreys with FontForge 2.0 (http://fontforge.sf.net) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.ttf b/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.ttf deleted file mode 100644 index 6cce217dd..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.ttf and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.woff b/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.woff deleted file mode 100644 index e2cfe25dd..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/icons/foundation-icons.woff and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/ajax-loader.gif b/browser-extensions/chrome/copay-chrome-extension/img/ajax-loader.gif deleted file mode 100644 index e1130fa6b..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/ajax-loader.gif and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/avatar.jpg b/browser-extensions/chrome/copay-chrome-extension/img/avatar.jpg deleted file mode 100644 index a6ef1372e..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/avatar.jpg and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/bank.svg b/browser-extensions/chrome/copay-chrome-extension/img/bank.svg deleted file mode 100644 index 343af7a9c..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/bank.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - Shape + Shape Copy - Created with Sketch. - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/bought-pending.svg b/browser-extensions/chrome/copay-chrome-extension/img/bought-pending.svg deleted file mode 100644 index 2ada9aaaf..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/bought-pending.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - -Oval 356 + ios7-redo -Created with Sketch. - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/bought.svg b/browser-extensions/chrome/copay-chrome-extension/img/bought.svg deleted file mode 100644 index 63c16f570..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/bought.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - -Oval 356 + ios7-redo + Shape Copy 5 -Created with Sketch. - - - - - - - - - - - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/buy-bitcoin.svg b/browser-extensions/chrome/copay-chrome-extension/img/buy-bitcoin.svg deleted file mode 100644 index ed4bb7fa3..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/buy-bitcoin.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - -fi-bitcoin-circle + Oval 356 + ios7-redo Copy 4 -Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/change-avatar.png b/browser-extensions/chrome/copay-chrome-extension/img/change-avatar.png deleted file mode 100644 index 6c0ed0826..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/change-avatar.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-pin-enter.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-pin-enter.png deleted file mode 100644 index 10af5f576..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-pin-enter.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-pin.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-pin.png deleted file mode 100644 index 77eb596c3..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-pin.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signin.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-signin.png deleted file mode 100644 index 169e04022..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signin.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup1.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup1.png deleted file mode 100644 index 546abf47e..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup1.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup2-1.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup2-1.png deleted file mode 100644 index 8cc3759d1..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup2-1.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup2.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup2.png deleted file mode 100644 index c536f02ba..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup2.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup3.png b/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup3.png deleted file mode 100644 index 0a16191cd..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/clipo-signup3.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/coinbase-logo-inverse.png b/browser-extensions/chrome/copay-chrome-extension/img/coinbase-logo-inverse.png deleted file mode 100644 index b6470219d..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/coinbase-logo-inverse.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/coinbase-logo.png b/browser-extensions/chrome/copay-chrome-extension/img/coinbase-logo.png deleted file mode 100644 index 53da54f52..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/coinbase-logo.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/copay_crowdin.png b/browser-extensions/chrome/copay-chrome-extension/img/copay_crowdin.png deleted file mode 100644 index 31695e998..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/copay_crowdin.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/favicon.ico b/browser-extensions/chrome/copay-chrome-extension/img/favicon.ico deleted file mode 100644 index e2f92139d..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/favicon.ico and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/glidera-logo.png b/browser-extensions/chrome/copay-chrome-extension/img/glidera-logo.png deleted file mode 100644 index 930cdf4a9..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/glidera-logo.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-activity.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-activity.svg deleted file mode 100644 index b24b17075..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-activity.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - downloadbox - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-bws-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-bws-white.svg deleted file mode 100644 index ad73056ee..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-bws-white.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-bws.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-bws.svg deleted file mode 100644 index 1d557ced9..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-bws.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - BWS + Rectangle 214 - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-email.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-email.svg deleted file mode 100644 index ad4efe592..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-email.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - email copy - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-ledger-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-ledger-white.svg deleted file mode 100644 index 37dbdab28..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-ledger-white.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-ledger.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-ledger.svg deleted file mode 100644 index 6c844dfb2..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-ledger.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-lock-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-lock-white.svg deleted file mode 100644 index 4d093a9cd..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-lock-white.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-lock.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-lock.svg deleted file mode 100644 index 578c0c3e1..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-lock.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - lock - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-moved.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-moved.svg deleted file mode 100644 index 96b2b78e7..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-moved.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - Oval 145 Copy 7 + retweet - Created with Sketch. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-new.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-new.svg deleted file mode 100644 index 71c7db6e1..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-new.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - Oval 145 Copy 7 + retweet - Created with Sketch. - - - - - Layer 1 - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-proposal.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-proposal.svg deleted file mode 100644 index 63e90d1b8..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-proposal.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - Oval 145 Copy 5 + send - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-read-only-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-read-only-white.svg deleted file mode 100644 index 933d6e0f6..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-read-only-white.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-read-only.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-read-only.svg deleted file mode 100644 index 1d6b116c0..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-read-only.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-receive-history.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-receive-history.svg deleted file mode 100644 index caa28e347..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-receive-history.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - Oval 145 Copy 5 + downloadbox - Created with Sketch. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-receive.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-receive.svg deleted file mode 100644 index 64209664e..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-receive.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - downloadbox - Created with Sketch. - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-send.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-send.svg deleted file mode 100644 index 677348300..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-send.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - send - Created with Sketch. - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-sent-history.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-sent-history.svg deleted file mode 100644 index cfb0426e5..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-sent-history.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - Oval 145 Copy 7 + send copy - Created with Sketch. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-sent.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-sent.svg deleted file mode 100644 index cfb0426e5..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-sent.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - Oval 145 Copy 7 + send copy - Created with Sketch. - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-splash.png b/browser-extensions/chrome/copay-chrome-extension/img/icon-splash.png deleted file mode 100644 index f917a1d87..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icon-splash.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-sync-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-sync-white.svg deleted file mode 100644 index 05a4a219f..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-sync-white.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-sync.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-sync.svg deleted file mode 100644 index a3245639d..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-sync.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - sync - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-testnet-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-testnet-white.svg deleted file mode 100644 index 537370ba3..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-testnet-white.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-testnet.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-testnet.svg deleted file mode 100644 index 6179fd715..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-testnet.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - flask - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-tour1.png b/browser-extensions/chrome/copay-chrome-extension/img/icon-tour1.png deleted file mode 100644 index c715239b7..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icon-tour1.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-trezor-white.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-trezor-white.svg deleted file mode 100644 index 5cd2a3254..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-trezor-white.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-trezor.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-trezor.svg deleted file mode 100644 index accc0866c..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-trezor.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-user.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-user.svg deleted file mode 100644 index 27417de6f..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-user.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - users - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-users.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-users.svg deleted file mode 100644 index 4afe0d6d5..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-users.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - usergroup - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-view.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-view.svg deleted file mode 100644 index d24d494b7..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-view.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - view - Created with Sketch. - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icon-wallet.svg b/browser-extensions/chrome/copay-chrome-extension/img/icon-wallet.svg deleted file mode 100644 index b8b642c96..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/icon-wallet.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - -Wallet-Copy -Created with Sketch. - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/copy.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/copy.png deleted file mode 100644 index b43ca0634..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/copy.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/favicon.ico b/browser-extensions/chrome/copay-chrome-extension/img/icons/favicon.ico deleted file mode 100644 index 03f394e70..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/favicon.ico and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-16.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-16.png deleted file mode 100644 index d4664c57a..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-16.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-256.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-256.png deleted file mode 100644 index f9978eb28..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-256.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-32.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-32.png deleted file mode 100644 index eca42cbc5..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-32.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-64.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-64.png deleted file mode 100644 index fec1daa73..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-64.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-chrome-128.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-chrome-128.png deleted file mode 100644 index 0044af9ca..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon-chrome-128.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.icns b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.icns deleted file mode 100644 index 8fc084681..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.icns and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.ico b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.ico deleted file mode 100644 index e40c22dcf..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.ico and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.png deleted file mode 100644 index 47cdc4b1f..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/icon.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/logo-chrome-256.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/logo-chrome-256.png deleted file mode 100644 index 803f97494..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/logo-chrome-256.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/icons/logo-chrome-64.png b/browser-extensions/chrome/copay-chrome-extension/img/icons/logo-chrome-64.png deleted file mode 100644 index b09c6b57a..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/icons/logo-chrome-64.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/img-tour1.png b/browser-extensions/chrome/copay-chrome-extension/img/img-tour1.png deleted file mode 100644 index 298c6b7e9..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/img-tour1.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/logo-negative-beta.svg b/browser-extensions/chrome/copay-chrome-extension/img/logo-negative-beta.svg deleted file mode 100644 index 156b7a3cd..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/logo-negative-beta.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - Imported Layers - Created with Sketch. - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/logo-negative.png b/browser-extensions/chrome/copay-chrome-extension/img/logo-negative.png deleted file mode 100644 index 522d1420f..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/logo-negative.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/logo-negative.svg b/browser-extensions/chrome/copay-chrome-extension/img/logo-negative.svg deleted file mode 100644 index ab7e62a89..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/logo-negative.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - Artboard 1 - Created with Sketch. - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/logo.png b/browser-extensions/chrome/copay-chrome-extension/img/logo.png deleted file mode 100644 index 01fe6c0bd..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/logo.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/logo.svg b/browser-extensions/chrome/copay-chrome-extension/img/logo.svg deleted file mode 100644 index 9f404535a..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/logo.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - -download 3 -Created with Sketch. - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/notification.png b/browser-extensions/chrome/copay-chrome-extension/img/notification.png deleted file mode 100644 index 70b0843c0..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/notification.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/qr.png b/browser-extensions/chrome/copay-chrome-extension/img/qr.png deleted file mode 100644 index a5e5212b7..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/qr.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/satoshi.gif b/browser-extensions/chrome/copay-chrome-extension/img/satoshi.gif deleted file mode 100644 index 0e5292df5..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/satoshi.gif and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/sell-bitcoin.svg b/browser-extensions/chrome/copay-chrome-extension/img/sell-bitcoin.svg deleted file mode 100644 index 8a313b76c..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/sell-bitcoin.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - -fi-bitcoin-circle copy + Oval 356 Copy + ios7-redo copy Copy -Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/sold-pending.svg b/browser-extensions/chrome/copay-chrome-extension/img/sold-pending.svg deleted file mode 100644 index d4b33f08a..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/sold-pending.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - -Oval 356 + ios7-redo Copy -Created with Sketch. - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/sold.svg b/browser-extensions/chrome/copay-chrome-extension/img/sold.svg deleted file mode 100644 index adade81d4..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/sold.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - -Oval 356 + ios7-redo Copy + Shape Copy 5 -Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/img/step-1.png b/browser-extensions/chrome/copay-chrome-extension/img/step-1.png deleted file mode 100644 index 43b2109d4..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/step-1.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/step-1.svg b/browser-extensions/chrome/copay-chrome-extension/img/step-1.svg deleted file mode 100644 index 50fc10493..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/step-1.svg +++ /dev/null @@ -1,30 +0,0 @@ - - - - Group@1x - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/step-2.png b/browser-extensions/chrome/copay-chrome-extension/img/step-2.png deleted file mode 100644 index 3a2844f63..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/step-2.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/step-2.svg b/browser-extensions/chrome/copay-chrome-extension/img/step-2.svg deleted file mode 100644 index 9a3cec072..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/step-2.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/step-3.png b/browser-extensions/chrome/copay-chrome-extension/img/step-3.png deleted file mode 100644 index 9a8c9493d..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/step-3.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/step-3.svg b/browser-extensions/chrome/copay-chrome-extension/img/step-3.svg deleted file mode 100644 index e6b50d55b..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/img/step-3.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser-extensions/chrome/copay-chrome-extension/img/tour1.png b/browser-extensions/chrome/copay-chrome-extension/img/tour1.png deleted file mode 100644 index 35fcdeace..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/tour1.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/tour2.png b/browser-extensions/chrome/copay-chrome-extension/img/tour2.png deleted file mode 100644 index c4f6d9c71..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/tour2.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/tour3.png b/browser-extensions/chrome/copay-chrome-extension/img/tour3.png deleted file mode 100644 index 49ccce917..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/tour3.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/tour4.png b/browser-extensions/chrome/copay-chrome-extension/img/tour4.png deleted file mode 100644 index abf73c671..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/tour4.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/img/tour5.png b/browser-extensions/chrome/copay-chrome-extension/img/tour5.png deleted file mode 100644 index 70cf157ed..000000000 Binary files a/browser-extensions/chrome/copay-chrome-extension/img/tour5.png and /dev/null differ diff --git a/browser-extensions/chrome/copay-chrome-extension/index.html b/browser-extensions/chrome/copay-chrome-extension/index.html deleted file mode 100644 index 4277f4235..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - Copay - Multisignature Wallet - - - - - - - - -
-
- - - - -
-
-
-
-
-
-
-
- - - - - - - - - - - - diff --git a/browser-extensions/chrome/copay-chrome-extension/initial.js b/browser-extensions/chrome/copay-chrome-extension/initial.js deleted file mode 100644 index 0ff1298cf..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/initial.js +++ /dev/null @@ -1,8 +0,0 @@ -chrome.app.runtime.onLaunched.addListener(function() { - chrome.app.window.create('index.html', { - 'bounds': { - 'width': 400, - 'height': 600 - } - }); -}); diff --git a/browser-extensions/chrome/copay-chrome-extension/js/app.js b/browser-extensions/chrome/copay-chrome-extension/js/app.js deleted file mode 100644 index 1fa8dc612..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/js/app.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -angular.module('cosign',[ - 'ngRoute', -]); diff --git a/browser-extensions/chrome/copay-chrome-extension/js/config.js b/browser-extensions/chrome/copay-chrome-extension/js/config.js deleted file mode 100644 index 68f6d43b5..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/js/config.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -//Setting up route -angular - .module('cosign') - .config(function($routeProvider) { - $routeProvider. - when('signin', { - templateUrl: '/views/signin.html', - title: 'Signin' - }) - .otherwise({ - templateUrl: '/views/404.html', - title: 'Error' - }); - }); - -//Setting HTML5 Location Mode -angular - .module('insight') - .config(function($locationProvider) { - $locationProvider.html5Mode(true); - $locationProvider.hashPrefix('!'); - }); diff --git a/browser-extensions/chrome/copay-chrome-extension/js/copay.js b/browser-extensions/chrome/copay-chrome-extension/js/copay.js deleted file mode 100644 index 659664ed7..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/js/copay.js +++ /dev/null @@ -1,14605 +0,0 @@ -'use strict'; - -var modules = [ - 'ui.router', - 'angularMoment', - 'monospaced.qrcode', - 'gettext', - 'ionic', - 'ngLodash', - 'ngSanitize', - 'ngCsv', - 'bwcModule', - 'copayApp.filters', - 'copayApp.services', - 'copayApp.controllers', - 'copayApp.directives', - 'copayApp.addons' -]; - -var copayApp = window.copayApp = angular.module('copayApp', modules); - -angular.module('copayApp.filters', []); -angular.module('copayApp.services', []); -angular.module('copayApp.controllers', []); -angular.module('copayApp.directives', []); -angular.module('copayApp.addons', []); - -'use strict'; - -var unsupported, isaosp; - -if (window && window.navigator) { - var rxaosp = window.navigator.userAgent.match(/Android.*AppleWebKit\/([\d.]+)/); - isaosp = (rxaosp && rxaosp[1] < 537); - if (!window.cordova && isaosp) - unsupported = true; - if (unsupported) { - window.location = '#/unsupported'; - } -} - -//Setting up route -angular.module('copayApp').config(function(historicLogProvider, $provide, $logProvider, $stateProvider, $urlRouterProvider, $compileProvider) { - $urlRouterProvider.otherwise('/'); - - $logProvider.debugEnabled(true); - $provide.decorator('$log', ['$delegate', 'platformInfo', - function($delegate, platformInfo) { - var historicLog = historicLogProvider.$get(); - - ['debug', 'info', 'warn', 'error', 'log'].forEach(function(level) { - if (platformInfo.isDevel && level == 'error') return; - - var orig = $delegate[level]; - $delegate[level] = function() { - if (level == 'error') - console.log(arguments); - - var args = Array.prototype.slice.call(arguments); - - args = args.map(function(v) { - try { - if (typeof v == 'undefined') v = 'undefined'; - if (!v) v = 'null'; - if (typeof v == 'object') { - if (v.message) - v = v.message; - else - v = JSON.stringify(v); - } - // Trim output in mobile - if (platformInfo.isCordova) { - v = v.toString(); - if (v.length > 3000) { - v = v.substr(0, 2997) + '...'; - } - } - } catch (e) { - console.log('Error at log decorator:', e); - v = 'undefined'; - } - return v; - }); - - try { - if (platformInfo.isCordova) - console.log(args.join(' ')); - - historicLog.add(level, args.join(' ')); - orig.apply(null, args); - } catch (e) { - console.log('ERROR (at log decorator):', e, args[0]); - } - }; - }); - return $delegate; - } - ]); - - // whitelist 'chrome-extension:' for chromeApp to work with image URLs processed by Angular - // link: http://stackoverflow.com/questions/15606751/angular-changes-urls-to-unsafe-in-extension-page?lq=1 - $compileProvider.imgSrcSanitizationWhitelist(/^\s*((https?|ftp|file|blob|chrome-extension):|data:image\/)/); - - $stateProvider - .state('translators', { - url: '/translators', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/translators.html' - } - } - }) - .state('disclaimer', { - url: '/disclaimer', - needProfile: false, - views: { - 'main': { - templateUrl: 'views/disclaimer.html', - } - } - }) - .state('walletHome', { - url: '/', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/walletHome.html', - }, - } - }) - .state('unsupported', { - url: '/unsupported', - needProfile: false, - views: { - 'main': { - templateUrl: 'views/unsupported.html' - } - } - }) - .state('uri', { - url: '/uri/:url', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/uri.html' - } - } - }) - .state('uripayment', { - url: '/uri-payment/:url', - templateUrl: 'views/paymentUri.html', - views: { - 'main': { - templateUrl: 'views/paymentUri.html', - }, - }, - needProfile: true - }) - .state('join', { - url: '/join', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/join.html' - }, - } - }) - .state('import', { - url: '/import', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/import.html' - }, - } - }) - .state('create', { - url: '/create', - templateUrl: 'views/create.html', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/create.html' - }, - } - }) - .state('copayers', { - url: '/copayers', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/copayers.html' - }, - } - }) - .state('preferences', { - url: '/preferences', - templateUrl: 'views/preferences.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferences.html', - }, - } - }) - .state('preferencesLanguage', { - url: '/preferencesLanguage', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesLanguage.html' - }, - } - }) - .state('preferencesUnit', { - url: '/preferencesUnit', - templateUrl: 'views/preferencesUnit.html', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesUnit.html' - }, - } - }) - .state('preferencesFee', { - url: '/preferencesFee', - templateUrl: 'views/preferencesFee.html', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesFee.html' - }, - } - }) - .state('uriglidera', { - url: '/uri-glidera/:url', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/glideraUri.html' - }, - } - }) - .state('glidera', { - url: '/glidera', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/glidera.html' - }, - } - }) - .state('buyGlidera', { - url: '/buy', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/buyGlidera.html' - }, - } - }) - .state('sellGlidera', { - url: '/sell', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/sellGlidera.html' - }, - } - }) - .state('preferencesGlidera', { - url: '/preferencesGlidera', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesGlidera.html' - }, - } - }) - .state('coinbase', { - url: '/coinbase', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/coinbase.html' - }, - } - }) - .state('preferencesCoinbase', { - url: '/preferencesCoinbase', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesCoinbase.html' - }, - } - }) - .state('uricoinbase', { - url: '/uri-coinbase/:url', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/coinbaseUri.html' - }, - } - }) - .state('buyCoinbase', { - url: '/buycoinbase', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/buyCoinbase.html' - }, - } - }) - .state('sellCoinbase', { - url: '/sellcoinbase', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/sellCoinbase.html' - }, - } - }) - .state('buyandsell', { - url: '/buyandsell', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/buyAndSell.html' - }, - } - }) - .state('preferencesAdvanced', { - url: '/preferencesAdvanced', - templateUrl: 'views/preferencesAdvanced.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesAdvanced.html' - }, - } - }) - .state('preferencesColor', { - url: '/preferencesColor', - templateUrl: 'views/preferencesColor.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesColor.html' - }, - } - }) - .state('preferencesAltCurrency', { - url: '/preferencesAltCurrency', - templateUrl: 'views/preferencesAltCurrency.html', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesAltCurrency.html' - }, - } - }) - .state('preferencesAlias', { - url: '/preferencesAlias', - templateUrl: 'views/preferencesAlias.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesAlias.html' - }, - - } - }) - .state('preferencesEmail', { - url: '/preferencesEmail', - templateUrl: 'views/preferencesEmail.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesEmail.html' - }, - - } - }) - .state('preferencesBwsUrl', { - url: '/preferencesBwsUrl', - templateUrl: 'views/preferencesBwsUrl.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesBwsUrl.html' - }, - - } - }) - .state('preferencesHistory', { - url: '/preferencesHistory', - templateUrl: 'views/preferencesHistory.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesHistory.html' - }, - - } - }) - .state('deleteWords', { - url: '/deleteWords', - templateUrl: 'views/preferencesDeleteWords.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesDeleteWords.html' - }, - } - }) - .state('delete', { - url: '/delete', - templateUrl: 'views/preferencesDeleteWallet.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesDeleteWallet.html' - }, - } - }) - .state('information', { - url: '/information', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesInformation.html' - }, - } - }) - .state('about', { - url: '/about', - templateUrl: 'views/preferencesAbout.html', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesAbout.html' - }, - } - }) - .state('logs', { - url: '/logs', - templateUrl: 'views/preferencesLogs.html', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesLogs.html' - }, - } - }) - .state('export', { - url: '/export', - templateUrl: 'views/export.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/export.html' - }, - } - }) - .state('paperWallet', { - url: '/paperWallet', - templateUrl: 'views/paperWallet.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/paperWallet.html' - }, - } - }) - .state('backup', { - url: '/backup', - templateUrl: 'views/backup.html', - walletShouldBeComplete: true, - needProfile: true, - views: { - 'main': { - templateUrl: 'views/backup.html' - }, - } - }) - .state('preferencesGlobal', { - url: '/preferencesGlobal', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/preferencesGlobal.html', - }, - } - }) - .state('termOfUse', { - url: '/termOfUse', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/termOfUse.html', - }, - } - }) - .state('add', { - url: '/add', - needProfile: true, - views: { - 'main': { - templateUrl: 'views/add.html' - }, - } - }); - }) - .run(function($rootScope, $state, $location, $log, $timeout, $ionicPlatform, lodash, platformInfo, profileService, uxLanguage, go, gettextCatalog) { - - if (platformInfo.isCordova) { - if (screen.width < 768) { - screen.lockOrientation('portrait'); - } else { - window.addEventListener("orientationchange", function() { - var leftMenuWidth = document.querySelector("ion-side-menu[side='left']").clientWidth; - if (screen.orientation.includes('portrait')) { - // Portrait - document.querySelector("ion-side-menu-content").style.width = (screen.width - leftMenuWidth) + "px"; - } else { - // Landscape - document.querySelector("ion-side-menu-content").style.width = (screen.height - leftMenuWidth) + "px"; - } - }); - } - } else { - if (screen.width >= 768) { - window.addEventListener('resize', lodash.throttle(function() { - $rootScope.$emit('Local/WindowResize'); - }, 100)); - } - } - - $ionicPlatform.ready(function() { - if (platformInfo.isCordova) { - - window.addEventListener('native.keyboardhide', function() { - $timeout(function() { - $rootScope.shouldHideMenuBar = false; //show menu bar when keyboard is hidden with back button action on send screen - }, 100); - }); - - window.addEventListener('native.keyboardshow', function() { - $timeout(function() { - $rootScope.shouldHideMenuBar = true; //hide menu bar when keyboard opens with back button action on send screen - }, 300); - }); - - if (window.cordova.plugins.Keyboard) { - cordova.plugins.Keyboard.hideKeyboardAccessoryBar(false); - cordova.plugins.Keyboard.disableScroll(false); - } - - $ionicPlatform.registerBackButtonAction(function(event) { - event.preventDefault(); - }, 100); - - var secondBackButtonPress = false; - var intval = setInterval(function() { - secondBackButtonPress = false; - }, 5000); - - $ionicPlatform.on('pause', function() { - // Nothing to do - }); - - $ionicPlatform.on('resume', function() { - $rootScope.$emit('Local/Resume'); - }); - - $ionicPlatform.on('backbutton', function(event) { - - var loc = window.location; - var fromDisclaimer = loc.toString().match(/disclaimer/) ? 'true' : ''; - var fromHome = loc.toString().match(/index\.html#\/$/) ? 'true' : ''; - - if (fromDisclaimer == 'true') - navigator.app.exitApp(); - - if (platformInfo.isMobile && fromHome == 'true') { - if (secondBackButtonPress) - navigator.app.exitApp(); - else - window.plugins.toast.showShortBottom(gettextCatalog.getString('Press again to exit')); - } - - if (secondBackButtonPress) - clearInterval(intval); - else - secondBackButtonPress = true; - - $timeout(function() { - $rootScope.$emit('Local/SetTab', 'walletHome', true); - }, 100); - - go.walletHome(); - }); - - $ionicPlatform.on('menubutton', function() { - window.location = '#/preferences'; - }); - - setTimeout(function() { - navigator.splashscreen.hide(); - }, 1000); - } - }); - - uxLanguage.init(); - - if (platformInfo.isNW) { - var gui = require('nw.gui'); - var win = gui.Window.get(); - var nativeMenuBar = new gui.Menu({ - type: "menubar" - }); - try { - nativeMenuBar.createMacBuiltin("Copay"); - } catch (e) { - $log.debug('This is not OSX'); - } - win.menu = nativeMenuBar; - } - - $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) { - $log.debug('Route change from:', fromState.name || '-', ' to:', toState.name); - $log.debug(' toParams:' + JSON.stringify(toParams || {})); - $log.debug(' fromParams:' + JSON.stringify(fromParams || {})); - - if (!profileService.profile && toState.needProfile) { - - // Give us time to open / create the profile - event.preventDefault(); - // Try to open local profile - profileService.loadAndBindProfile(function(err) { - if (err) { - if (err.message && err.message.match('NOPROFILE')) { - $log.debug('No profile... redirecting'); - $state.transitionTo('disclaimer'); - } else if (err.message && err.message.match('NONAGREEDDISCLAIMER')) { - $log.debug('Display disclaimer... redirecting'); - $state.transitionTo('disclaimer'); - } else { - throw new Error(err); // TODO - } - } else { - profileService.storeProfileIfDirty(); - $log.debug('Profile loaded ... Starting UX.'); - $state.transitionTo(toState.name || toState, toParams); - } - }); - } else { - if (profileService.focusedClient && !profileService.focusedClient.isComplete() && toState.walletShouldBeComplete) { - - $state.transitionTo('copayers'); - } - } - }); - }); - -'use strict'; - -function selectText(element) { - var doc = document; - if (doc.body.createTextRange) { // ms - var range = doc.body.createTextRange(); - range.moveToElementText(element); - range.select(); - } else if (window.getSelection) { - var selection = window.getSelection(); - var range = doc.createRange(); - range.selectNodeContents(element); - selection.removeAllRanges(); - selection.addRange(range); - - } -} -angular.module('copayApp.directives') - .directive('validAddress', ['$rootScope', 'bitcore', 'profileService', - function($rootScope, bitcore, profileService) { - return { - require: 'ngModel', - link: function(scope, elem, attrs, ctrl) { - var URI = bitcore.URI; - var Address = bitcore.Address - var validator = function(value) { - if (!profileService.focusedClient) - return; - var networkName = profileService.focusedClient.credentials.network; - // Regular url - if (/^https?:\/\//.test(value)) { - ctrl.$setValidity('validAddress', true); - return value; - } - - // Bip21 uri - if (/^bitcoin:/.test(value)) { - var uri, isAddressValid; - var isUriValid = URI.isValid(value); - if (isUriValid) { - uri = new URI(value); - isAddressValid = Address.isValid(uri.address.toString(), networkName) - } - ctrl.$setValidity('validAddress', isUriValid && isAddressValid); - return value; - } - - if (typeof value == 'undefined') { - ctrl.$pristine = true; - return; - } - - // Regular Address - ctrl.$setValidity('validAddress', Address.isValid(value, networkName)); - return value; - }; - - - ctrl.$parsers.unshift(validator); - ctrl.$formatters.unshift(validator); - } - }; - } - ]) - .directive('validUrl', [ - - function() { - return { - require: 'ngModel', - link: function(scope, elem, attrs, ctrl) { - var validator = function(value) { - // Regular url - if (/^https?:\/\//.test(value)) { - ctrl.$setValidity('validUrl', true); - return value; - } else { - ctrl.$setValidity('validUrl', false); - return value; - } - }; - - ctrl.$parsers.unshift(validator); - ctrl.$formatters.unshift(validator); - } - }; - } - ]) - .directive('validAmount', ['configService', - function(configService) { - - return { - require: 'ngModel', - link: function(scope, element, attrs, ctrl) { - var val = function(value) { - var settings = configService.getSync().wallet.settings; - var vNum = Number((value * settings.unitToSatoshi).toFixed(0)); - if (typeof value == 'undefined' || value == 0) { - ctrl.$pristine = true; - } - - - - if (typeof vNum == "number" && vNum > 0) { - if (vNum > Number.MAX_SAFE_INTEGER) { - ctrl.$setValidity('validAmount', false); - } else { - var decimals = Number(settings.unitDecimals); - var sep_index = ('' + value).indexOf('.'); - var str_value = ('' + value).substring(sep_index + 1); - if (sep_index >= 0 && str_value.length > decimals) { - ctrl.$setValidity('validAmount', false); - return; - } else { - ctrl.$setValidity('validAmount', true); - } - } - } else { - ctrl.$setValidity('validAmount', false); - } - return value; - } - ctrl.$parsers.unshift(val); - ctrl.$formatters.unshift(val); - } - }; - } - ]) - .directive('walletSecret', function(bitcore) { - return { - require: 'ngModel', - link: function(scope, elem, attrs, ctrl) { - var validator = function(value) { - if (value.length > 0) { - var m = value.match(/^[0-9A-HJ-NP-Za-km-z]{70,80}$/); - ctrl.$setValidity('walletSecret', m ? true : false); - } - return value; - }; - - ctrl.$parsers.unshift(validator); - } - }; - }) - .directive('loading', function() { - return { - restrict: 'A', - link: function($scope, element, attr) { - var a = element.html(); - var text = attr.loading; - element.on('click', function() { - element.html(' ' + text + '...'); - }); - $scope.$watch('loading', function(val) { - if (!val) { - element.html(a); - } - }); - } - } - }) - .directive('ngFileSelect', function() { - return { - link: function($scope, el) { - el.bind('change', function(e) { - $scope.file = (e.srcElement || e.target).files[0]; - $scope.getFile(); - }); - } - } - }) - .directive('contact', ['addressbookService', - function(addressbookService) { - return { - restrict: 'E', - link: function(scope, element, attrs) { - var addr = attrs.address; - addressbookService.getLabel(addr, function(label) { - if (label) { - element.append(label); - } else { - element.append(addr); - } - }); - } - }; - } - ]) - .directive('highlightOnChange', function() { - return { - restrict: 'A', - link: function(scope, element, attrs) { - scope.$watch(attrs.highlightOnChange, function(newValue, oldValue) { - element.addClass('highlight'); - setTimeout(function() { - element.removeClass('highlight'); - }, 500); - }); - } - } - }) - .directive('checkStrength', function() { - return { - replace: false, - restrict: 'EACM', - require: 'ngModel', - link: function(scope, element, attrs) { - - var MIN_LENGTH = 8; - var MESSAGES = ['Very Weak', 'Very Weak', 'Weak', 'Medium', 'Strong', 'Very Strong']; - var COLOR = ['#dd514c', '#dd514c', '#faa732', '#faa732', '#16A085', '#16A085']; - - function evaluateMeter(password) { - var passwordStrength = 0; - var text; - if (password.length > 0) passwordStrength = 1; - if (password.length >= MIN_LENGTH) { - if ((password.match(/[a-z]/)) && (password.match(/[A-Z]/))) { - passwordStrength++; - } else { - text = ', add mixed case'; - } - if (password.match(/\d+/)) { - passwordStrength++; - } else { - if (!text) text = ', add numerals'; - } - if (password.match(/.[!,@,#,$,%,^,&,*,?,_,~,-,(,)]/)) { - passwordStrength++; - } else { - if (!text) text = ', add punctuation'; - } - if (password.length > 12) { - passwordStrength++; - } else { - if (!text) text = ', add characters'; - } - } else { - text = ', that\'s short'; - } - if (!text) text = ''; - - return { - strength: passwordStrength, - message: MESSAGES[passwordStrength] + text, - color: COLOR[passwordStrength] - } - } - - scope.$watch(attrs.ngModel, function(newValue, oldValue) { - if (newValue && newValue !== '') { - var info = evaluateMeter(newValue); - scope[attrs.checkStrength] = info; - } - }); - } - }; - }) - .directive('showFocus', function($timeout) { - return function(scope, element, attrs) { - scope.$watch(attrs.showFocus, - function(newValue) { - $timeout(function() { - newValue && element[0].focus(); - }); - }, true); - }; - }) - .directive('match', function() { - return { - require: 'ngModel', - restrict: 'A', - scope: { - match: '=' - }, - link: function(scope, elem, attrs, ctrl) { - scope.$watch(function() { - return (ctrl.$pristine && angular.isUndefined(ctrl.$modelValue)) || scope.match === ctrl.$modelValue; - }, function(currentValue) { - ctrl.$setValidity('match', currentValue); - }); - } - }; - }) - .directive('clipCopy', function() { - return { - restrict: 'A', - scope: { - clipCopy: '=clipCopy' - }, - link: function(scope, elm) { - // TODO this does not work (FIXME) - elm.attr('tooltip', 'Press Ctrl+C to Copy'); - elm.attr('tooltip-placement', 'top'); - - elm.bind('click', function() { - selectText(elm[0]); - }); - } - }; - }) - .directive('menuToggle', function() { - return { - restrict: 'E', - replace: true, - templateUrl: 'views/includes/menu-toggle.html' - } - }) - .directive('logo', function() { - return { - restrict: 'E', - scope: { - width: "@", - negative: "=" - }, - controller: function($scope) { - $scope.logo_url = $scope.negative ? 'img/logo-negative.svg' : 'img/logo.svg'; - }, - replace: true, - template: 'Copay' - } - }) - .directive('availableBalance', function() { - return { - restrict: 'E', - replace: true, - templateUrl: 'views/includes/available-balance.html' - } - }) - .directive('ignoreMouseWheel', function($rootScope, $timeout) { - return { - restrict: 'A', - link: function(scope, element, attrs) { - element.bind('mousewheel', function(event) { - element[0].blur(); - $timeout(function() { - element[0].focus(); - }, 1); - }); - } - } - }); - -'use strict'; - -angular.module('copayApp.directives') - .directive('qrScanner', function($rootScope, $timeout, $ionicModal, gettextCatalog, platformInfo) { - - var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; - var isIOS = platformInfo.isIOS; - - var controller = function($scope) { - - var onSuccess = function(result) { - $timeout(function() { - window.plugins.spinnerDialog.hide(); - }, 100); - if (isWP && result.cancelled) return; - - $timeout(function() { - var data = isIOS ? result : result.text; - $scope.onScan({ - data: data - }); - }, 1000); - }; - - var onError = function(error) { - $timeout(function() { - window.plugins.spinnerDialog.hide(); - }, 100); - }; - - $scope.cordovaOpenScanner = function() { - window.plugins.spinnerDialog.show(null, gettextCatalog.getString('Preparing camera...'), true); - $timeout(function() { - if (isIOS) { - cloudSky.zBar.scan({}, onSuccess, onError); - } else { - cordova.plugins.barcodeScanner.scan(onSuccess, onError); - } - if ($scope.beforeScan) { - $scope.beforeScan(); - } - }, 100); - }; - - $scope.modalOpenScanner = function() { - $ionicModal.fromTemplateUrl('views/modals/scanner.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.scannerModal = modal; - $scope.scannerModal.show(); - }); - }; - - $scope.openScanner = function() { - if (isCordova) { - $scope.cordovaOpenScanner(); - } else { - $scope.modalOpenScanner(); - } - }; - }; - - return { - restrict: 'E', - scope: { - onScan: "&", - beforeScan: "&" - }, - controller: controller, - replace: true, - template: '' - } - }); - -'use strict'; - -angular.module('copayApp.filters', []) - .filter('amTimeAgo', ['amMoment', - function(amMoment) { - return function(input) { - return amMoment.preprocessDate(input).fromNow(); - }; - } - ]) - .filter('paged', function() { - return function(elements) { - if (elements) { - return elements.filter(Boolean); - } - - return false; - }; - }) - .filter('removeEmpty', function() { - return function(elements) { - elements = elements || []; - // Hide empty change addresses from other copayers - return elements.filter(function(e) { - return !e.isChange || e.balance > 0; - }); - } - }) - .filter('formatFiatAmount', ['$filter', '$locale', 'configService', - function(filter, locale, configService) { - var numberFilter = filter('number'); - var formats = locale.NUMBER_FORMATS; - var config = configService.getSync().wallet.settings; - return function(amount) { - if (!config) return amount; - - var fractionSize = 2; - var value = numberFilter(amount, fractionSize); - var sep = value.indexOf(formats.DECIMAL_SEP); - var group = value.indexOf(formats.GROUP_SEP); - - if (amount >= 0) { - if (group > 0) { - if (sep < 0) { - return value; - } - var intValue = value.substring(0, sep); - var floatValue = parseFloat(value.substring(sep)); - floatValue = floatValue.toFixed(2); - floatValue = floatValue.toString().substring(1); - var finalValue = intValue + floatValue; - return finalValue; - } else { - value = parseFloat(value); - return value.toFixed(2); - } - } - return 0; - }; - } - ]) - .filter('orderObjectBy', function() { - return function(items, field, reverse) { - var filtered = []; - angular.forEach(items, function(item) { - filtered.push(item); - }); - filtered.sort(function(a, b) { - return (a[field] > b[field] ? 1 : -1); - }); - if (reverse) filtered.reverse(); - return filtered; - }; - }); - -'use strict'; - -/** - * Profile - * - * credential: array of OBJECTS - */ -function Profile() { - this.version = '1.0.0'; -}; - -Profile.create = function(opts) { - opts = opts || {}; - - var x = new Profile(); - x.createdOn = Date.now(); - x.credentials = opts.credentials || []; - x.disclaimerAccepted = false; - x.checked = {}; - return x; -}; - -Profile.fromObj = function(obj) { - var x = new Profile(); - - x.createdOn = obj.createdOn; - x.credentials = obj.credentials; - x.disclaimerAccepted = obj.disclaimerAccepted; - x.checked = obj.checked || {}; - x.checkedUA = obj.checkedUA || {}; - - if (x.credentials[0] && typeof x.credentials[0] != 'object') - throw ("credentials should be an object"); - - return x; -}; - -Profile.fromString = function(str) { - return Profile.fromObj(JSON.parse(str)); -}; - -Profile.prototype.toObj = function() { - delete this.dirty; - return JSON.stringify(this); -}; - - -Profile.prototype.hasWallet = function(walletId) { - for (var i in this.credentials) { - var c = this.credentials[i]; - if (c.walletId == walletId) return true; - }; - return false; -}; - -Profile.prototype.isChecked = function(ua, walletId) { - return !!(this.checkedUA == ua && this.checked[walletId]); -}; - - -Profile.prototype.isDeviceChecked = function(ua) { - return this.checkedUA == ua; -}; - - -Profile.prototype.setChecked = function(ua, walletId) { - if (this.checkedUA != ua) { - this.checkedUA = ua; - this.checked = {}; - } - this.checked[walletId] = true; - this.dirty = true; -}; - - -Profile.prototype.addWallet = function(credentials) { - if (!credentials.walletId) - throw 'credentials must have .walletId'; - - if (this.hasWallet(credentials.walletId)) - return false; - - this.credentials.push(credentials); - this.dirty = true; - return true; -}; - -Profile.prototype.updateWallet = function(credentials) { - if (!credentials.walletId) - throw 'credentials must have .walletId'; - - if (!this.hasWallet(credentials.walletId)) - return false; - - this.credentials = this.credentials.map(function(c) { - if(c.walletId != credentials.walletId ) { - return c; - } else { - return credentials - } - }); - - this.dirty = true; - return true; -}; - -Profile.prototype.deleteWallet = function(walletId) { - if (!this.hasWallet(walletId)) - return false; - - this.credentials = this.credentials.filter(function(c) { - return c.walletId != walletId; - }); - - this.dirty = true; - return true; -}; - -'use strict'; - -angular.module('copayApp.services').service('addonManager', function (lodash) { - var addons = []; - - this.registerAddon = function (addonSpec) { - addons.push(addonSpec); - }; - - this.addonMenuItems = function () { - return lodash.map(addons, function (addonSpec) { - return addonSpec.menuItem; - }); - }; - - this.addonViews = function () { - return lodash.map(addons, function (addonSpec) { - return addonSpec.view; - }); - }; - - this.formatPendingTxp = function (txp) { - lodash.each(addons, function (addon) { - if (addon.formatPendingTxp) { - addon.formatPendingTxp(txp); - } - }); - }; - - this.txTemplateUrl = function() { - var addon = lodash.find(addons, 'txTemplateUrl'); - return addon ? addon.txTemplateUrl() : null; - } -}); - -'use strict'; -'use strict'; -angular.module('copayApp.services') - .factory('addressService', function(storageService, profileService, $log, $timeout, lodash, bwcError, gettextCatalog) { - var root = {}; - - root.expireAddress = function(walletId, cb) { - $log.debug('Cleaning Address ' + walletId); - storageService.clearLastAddress(walletId, function(err) { - return cb(err); - }); - }; - - root.isUsed = function(walletId, byAddress, cb) { - storageService.getLastAddress(walletId, function(err, addr) { - var used = lodash.find(byAddress, { - address: addr - }); - return cb(null, used); - }); - }; - - root._createAddress = function(walletId, cb) { - var client = profileService.getClient(walletId); - - $log.debug('Creating address for wallet:', walletId); - - client.createAddress({}, function(err, addr) { - if (err) { - var prefix = gettextCatalog.getString('Could not create address'); - if (err.error && err.error.match(/locked/gi)) { - $log.debug(err.error); - return $timeout(function() { - root._createAddress(walletId, cb); - }, 5000); - } else if (err.message && err.message == 'MAIN_ADDRESS_GAP_REACHED') { - $log.warn(err.message); - prefix = null; - client.getMainAddresses({ - reverse: true, - limit: 1 - }, function(err, addr) { - if (err) return cb(err); - return cb(null, addr[0].address); - }); - } - return bwcError.cb(err, prefix, cb); - } - return cb(null, addr.address); - }); - }; - - root.getAddress = function(walletId, forceNew, cb) { - - var firstStep; - if (forceNew) { - firstStep = storageService.clearLastAddress; - } else { - firstStep = function(walletId, cb) { - return cb(); - }; - } - - firstStep(walletId, function(err) { - if (err) return cb(err); - - storageService.getLastAddress(walletId, function(err, addr) { - if (err) return cb(err); - - if (addr) return cb(null, addr); - - root._createAddress(walletId, function(err, addr) { - if (err) return cb(err); - storageService.storeLastAddress(walletId, addr, function() { - if (err) return cb(err); - return cb(null, addr); - }); - }); - }); - }); - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services').factory('addressbookService', function(storageService, profileService) { - var root = {}; - - root.getLabel = function(addr, cb) { - var fc = profileService.focusedClient; - storageService.getAddressbook(fc.credentials.network, function(err, ab) { - if (!ab) return cb(); - ab = JSON.parse(ab); - if (ab[addr]) return cb(ab[addr]); - else return cb(); - }); - }; - - root.list = function(cb) { - var fc = profileService.focusedClient; - storageService.getAddressbook(fc.credentials.network, function(err, ab) { - if (err) return cb('Could not get the Addressbook'); - if (ab) ab = JSON.parse(ab); - return cb(err, ab); - }); - }; - - root.add = function(entry, cb) { - var fc = profileService.focusedClient; - root.list(function(err, ab) { - if (err) return cb(err); - if (!ab) ab = {}; - if (ab[entry.address]) return cb('Entry already exist'); - ab[entry.address] = entry.label; - storageService.setAddressbook(fc.credentials.network, JSON.stringify(ab), function(err, ab) { - if (err) return cb('Error adding new entry'); - root.list(function(err, ab) { - return cb(err, ab); - }); - }); - }); - }; - - root.remove = function(addr, cb) { - var fc = profileService.focusedClient; - root.list(function(err, ab) { - if (err) return cb(err); - if (!ab) return; - if (!ab[addr]) return cb('Entry does not exist'); - delete ab[addr]; - storageService.setAddressbook(fc.credentials.network, JSON.stringify(ab), function(err) { - if (err) return cb('Error deleting entry'); - root.list(function(err, ab) { - return cb(err, ab); - }); - }); - }); - }; - - root.removeAll = function() { - var fc = profileService.focusedClient; - storageService.removeAddressbook(fc.credentials.network, function(err) { - if (err) return cb('Error deleting addressbook'); - return cb(); - }); - }; - - return root; -}); - -'use strict'; -angular.module('copayApp.services') - .factory('applicationService', function($rootScope, $timeout, platformInfo, go) { - var root = {}; - - var isChromeApp = platformInfo.isChromeApp; - var isNW = platformInfo.isNW; - - root.restart = function() { - var hashIndex = window.location.href.indexOf('#/'); - if (platformInfo.isCordova) { - window.location = window.location.href.substr(0, hashIndex); - $timeout(function() { - $rootScope.$digest(); - }, 1); - - } else { - // Go home reloading the application - if (isChromeApp) { - chrome.runtime.reload(); - } else if (isNW) { - go.walletHome(); - $timeout(function() { - var win = require('nw.gui').Window.get(); - win.reload(3); - //or - win.reloadDev(); - }, 100); - } else { - window.location = window.location.href.substr(0, hashIndex); - } - } - }; - - return root; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('backupService', function backupServiceFactory($log, $timeout, profileService, sjcl) { - - var root = {}; - - var _download = function(ew, filename, cb) { - var NewBlob = function(data, datatype) { - var out; - - try { - out = new Blob([data], { - type: datatype - }); - $log.debug("case 1"); - } catch (e) { - window.BlobBuilder = window.BlobBuilder || - window.WebKitBlobBuilder || - window.MozBlobBuilder || - window.MSBlobBuilder; - - if (e.name == 'TypeError' && window.BlobBuilder) { - var bb = new BlobBuilder(); - bb.append(data); - out = bb.getBlob(datatype); - $log.debug("case 2"); - } else if (e.name == "InvalidStateError") { - // InvalidStateError (tested on FF13 WinXP) - out = new Blob([data], { - type: datatype - }); - $log.debug("case 3"); - } else { - // We're screwed, blob constructor unsupported entirely - $log.debug("Error"); - } - } - return out; - }; - - var a = angular.element(''); - var blob = new NewBlob(ew, 'text/plain;charset=utf-8'); - a.attr('href', window.URL.createObjectURL(blob)); - a.attr('download', filename); - a[0].click(); - return cb(); - }; - - root.addMetadata = function(b, opts) { - - b = JSON.parse(b); - if (opts.addressBook) b.addressBook = opts.addressBook; - return JSON.stringify(b); - } - - root.walletExport = function(password, opts) { - if (!password) { - return null; - } - var fc = profileService.focusedClient; - try { - opts = opts || {}; - var b = fc.export(opts); - if (opts.addressBook) b = root.addMetadata(b, opts); - - var e = sjcl.encrypt(password, b, { - iter: 10000 - }); - return e; - } catch (err) { - $log.debug('Error exporting wallet: ', err); - return null; - }; - }; - - root.walletDownload = function(password, opts, cb) { - var fc = profileService.focusedClient; - var ew = root.walletExport(password, opts); - if (!ew) return cb('Could not create backup'); - - var walletName = (fc.alias || '') + (fc.alias ? '-' : '') + fc.credentials.walletName; - if (opts.noSign) walletName = walletName + '-noSign' - var filename = walletName + '-Copaybackup.aes.json'; - _download(ew, filename, cb) - }; - return root; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('bitcore', function bitcoreFactory(bwcService) { - var bitcore = bwcService.getBitcore(); - return bitcore; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('bwcError', function bwcErrorService($log, gettextCatalog) { - var root = {}; - - root.msg = function(err, prefix) { - if (!err) - return 'Unknown error'; - - var name; - - if (err.name) { - if (err.name == 'Error') - name = err.message - else - name = err.name.replace(/^bwc.Error/g, ''); - } else - name = err; - - var body = ''; - prefix = prefix || ''; - - if (name) { - switch (name) { - case 'INVALID_BACKUP': - body = gettextCatalog.getString('Wallet Recovery Phrase is invalid'); - break; - case 'WALLET_DOES_NOT_EXIST': - body = gettextCatalog.getString('Wallet not registered at the wallet service. Recreate it from "Create Wallet" using "Advanced Options" to set your recovery phrase'); - break; - case 'MISSING_PRIVATE_KEY': - body = gettextCatalog.getString('Missing private keys to sign'); - break; - case 'ENCRYPTED_PRIVATE_KEY': - body = gettextCatalog.getString('Private key is encrypted, cannot sign'); - break; - case 'SERVER_COMPROMISED': - body = gettextCatalog.getString('Server response could not be verified'); - break; - case 'COULD_NOT_BUILD_TRANSACTION': - body = gettextCatalog.getString('Could not build transaction'); - break; - case 'INSUFFICIENT_FUNDS': - body = gettextCatalog.getString('Insufficient funds'); - break; - case 'CONNECTION_ERROR': - body = gettextCatalog.getString('Network connection error'); - break; - case 'NOT_FOUND': - body = gettextCatalog.getString('Wallet service not found'); - break; - case 'ECONNRESET_ERROR': - body = gettextCatalog.getString('Connection reset by peer'); - break; - case 'BAD_RESPONSE_CODE': - body = gettextCatalog.getString('The request could not be understood by the server'); - break; - case 'WALLET_ALREADY_EXISTS': - body = gettextCatalog.getString('Wallet already exists'); - break; - case 'COPAYER_IN_WALLET': - body = gettextCatalog.getString('Copayer already in this wallet'); - break; - case 'WALLET_FULL': - body = gettextCatalog.getString('Wallet is full'); - break; - case 'WALLET_NOT_FOUND': - body = gettextCatalog.getString('Wallet not found'); - break; - case 'INSUFFICIENT_FUNDS_FOR_FEE': - body = gettextCatalog.getString('Insufficient funds for fee'); - break; - case 'LOCKED_FUNDS': - body = gettextCatalog.getString('Funds are locked by pending spend proposals'); - break; - case 'COPAYER_VOTED': - body = gettextCatalog.getString('Copayer already voted on this spend proposal'); - break; - case 'NOT_AUTHORIZED': - body = gettextCatalog.getString('Not authorized'); - break; - case 'TX_ALREADY_BROADCASTED': - body = gettextCatalog.getString('Transaction already broadcasted'); - break; - case 'TX_CANNOT_CREATE': - body = gettextCatalog.getString('Locktime in effect. Please wait to create a new spend proposal'); - break; - case 'TX_CANNOT_REMOVE': - body = gettextCatalog.getString('Locktime in effect. Please wait to remove this spend proposal'); - break; - case 'TX_NOT_ACCEPTED': - body = gettextCatalog.getString('Spend proposal is not accepted'); - break; - case 'TX_NOT_FOUND': - body = gettextCatalog.getString('Spend proposal not found'); - break; - case 'TX_NOT_PENDING': - body = gettextCatalog.getString('The spend proposal is not pending'); - break; - case 'UPGRADE_NEEDED': - body = gettextCatalog.getString('Please upgrade Copay to perform this action'); - break; - case 'BAD_SIGNATURES': - body = gettextCatalog.getString('Signatures rejected by server'); - break; - case 'COPAYER_DATA_MISMATCH': - body = gettextCatalog.getString('Copayer data mismatch'); - break; - case 'DUST_AMOUNT': - body = gettextCatalog.getString('Amount below minimum allowed'); - break; - case 'INCORRECT_ADDRESS_NETWORK': - body = gettextCatalog.getString('Incorrect address network'); - break; - case 'COPAYER_REGISTERED': - body = gettextCatalog.getString('Key already associated with an existing wallet'); - break; - case 'INVALID_ADDRESS': - body = gettextCatalog.getString('Invalid address'); - break; - case 'MAIN_ADDRESS_GAP_REACHED': - body = gettextCatalog.getString('Empty addresses limit reached. New addresses cannot be generated.'); - break; - case 'WALLET_LOCKED': - body = gettextCatalog.getString('Wallet is locked'); - break; - case 'WALLET_NOT_COMPLETE': - body = gettextCatalog.getString('Wallet is not complete'); - break; - case 'WALLET_NEEDS_BACKUP': - body = gettextCatalog.getString('Wallet needs backup'); - break; - case 'MISSING_PARAMETER': - body = gettextCatalog.getString('Missing parameter'); - break; - case 'NO_PASSWORD_GIVEN': - body = gettextCatalog.getString('Spending Password needed'); - break; - case 'PASSWORD_INCORRECT': - body = gettextCatalog.getString('Wrong spending password'); - break; - case 'ERROR': - body = (err.message || err.error); - break; - - default: - $log.warn('Unknown error type:', name); - body = err.message || name; - break; - } - } else if (err.message) { - body = err.message; - } else { - body = err; - } - - var msg = prefix + (body ? (prefix ? ': ' : '') + body : ''); - return msg; - }; - - root.cb = function(err, prefix, cb) { - return cb(root.msg(err, prefix)); - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services').factory('coinbaseService', function($http, $log, platformInfo, lodash, storageService, configService) { - var root = {}; - var credentials = {}; - var isCordova = platformInfo.isCordova; - - root.setCredentials = function(network) { - credentials.SCOPE = '' - + 'wallet:accounts:read,' - + 'wallet:addresses:read,' - + 'wallet:addresses:create,' - + 'wallet:user:read,' - + 'wallet:user:email,' - + 'wallet:buys:read,' - + 'wallet:buys:create,' - + 'wallet:sells:read,' - + 'wallet:sells:create,' - + 'wallet:transactions:read,' - + 'wallet:transactions:send,' - + 'wallet:payment-methods:read'; - - if (isCordova) { - credentials.REDIRECT_URI = 'copay://coinbase'; - } else { - credentials.REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'; - } - - if (network == 'testnet') { - credentials.HOST = 'https://sandbox.coinbase.com'; - credentials.API = 'https://api.sandbox.coinbase.com'; - credentials.CLIENT_ID = '6cdcc82d5d46654c46880e93ab3d2a43c639776347dd88022904bd78cd067841'; - credentials.CLIENT_SECRET = '228cb6308951f4b6f41ba010c7d7981b2721a493c40c50fd2425132dcaccce59'; - } - else { - credentials.HOST = 'https://coinbase.com'; - credentials.API = 'https://api.coinbase.com'; - credentials.CLIENT_ID = window.coinbase_client_id; - credentials.CLIENT_SECRET = window.coinbase_client_secret; - }; - }; - - root.getOauthCodeUrl = function() { - return credentials.HOST - + '/oauth/authorize?response_type=code&client_id=' - + credentials.CLIENT_ID - + '&redirect_uri=' - + credentials.REDIRECT_URI - + '&state=SECURE_RANDOM&scope=' - + credentials.SCOPE - + '&meta[send_limit_amount]=1000&meta[send_limit_currency]=USD&meta[send_limit_period]=day'; - }; - - root.getToken = function(code, cb) { - var req = { - method: 'POST', - url: credentials.API + '/oauth/token', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - data: { - grant_type : 'authorization_code', - code: code, - client_id : credentials.CLIENT_ID, - client_secret: credentials.CLIENT_SECRET, - redirect_uri: credentials.REDIRECT_URI - } - }; - - $http(req).then(function(data) { - $log.info('Coinbase Authorization Access Token: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Authorization Access Token: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.refreshToken = function(refreshToken, cb) { - var req = { - method: 'POST', - url: credentials.API + '/oauth/token', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - data: { - grant_type : 'refresh_token', - client_id : credentials.CLIENT_ID, - client_secret: credentials.CLIENT_SECRET, - redirect_uri: credentials.REDIRECT_URI, - refresh_token: refreshToken - } - }; - - $http(req).then(function(data) { - $log.info('Coinbase Refresh Access Token: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Refresh Access Token: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - var _get = function(endpoint, token) { - return { - method: 'GET', - url: credentials.API + '/v2' + endpoint, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - }; - }; - - root.getAccounts = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/accounts', token)).then(function(data) { - $log.info('Coinbase Get Accounts: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Get Accounts: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getAccount = function(token, accountId, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/accounts/' + accountId, token)).then(function(data) { - $log.info('Coinbase Get Account: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Get Account: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getAuthorizationInformation = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user/auth', token)).then(function(data) { - $log.info('Coinbase Autorization Information: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Autorization Information: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getCurrentUser = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user', token)).then(function(data) { - $log.info('Coinbase Get Current User: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Get Current User: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getTransaction = function(token, accountId, transactionId, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/accounts/' + accountId + '/transactions/' + transactionId, token)).then(function(data) { - $log.info('Coinbase Transaction: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Transaction: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getTransactions = function(token, accountId, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/accounts/' + accountId + '/transactions', token)).then(function(data) { - $log.info('Coinbase Transactions: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Transactions: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.paginationTransactions = function(token, Url, cb) { - if (!token) return cb('Invalid Token'); - $http(_get(Url.replace('/v2', ''), token)).then(function(data) { - $log.info('Coinbase Pagination Transactions: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Pagination Transactions: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.sellPrice = function(token, currency, cb) { - $http(_get('/prices/sell?currency=' + currency, token)).then(function(data) { - $log.info('Coinbase Sell Price: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Sell Price: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.buyPrice = function(token, currency, cb) { - $http(_get('/prices/buy?currency=' + currency, token)).then(function(data) { - $log.info('Coinbase Buy Price: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Buy Price: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getPaymentMethods = function(token, cb) { - $http(_get('/payment-methods', token)).then(function(data) { - $log.info('Coinbase Get Payment Methods: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Get Payment Methods: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.getPaymentMethod = function(token, paymentMethodId, cb) { - $http(_get('/payment-methods/' + paymentMethodId, token)).then(function(data) { - $log.info('Coinbase Get Payment Method: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Get Payment Method: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - var _post = function(endpoint, token, data) { - return { - method: 'POST', - url: credentials.API + '/v2' + endpoint, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - }, - data: data - }; - }; - - root.sellRequest = function(token, accountId, data, cb) { - var data = { - amount: data.amount, - currency: data.currency, - payment_method: data.payment_method || null, - commit: data.commit || false - }; - $http(_post('/accounts/' + accountId + '/sells', token, data)).then(function(data) { - $log.info('Coinbase Sell Request: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Sell Request: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.sellCommit = function(token, accountId, sellId, cb) { - $http(_post('/accounts/' + accountId + '/sells/' + sellId + '/commit', token)).then(function(data) { - $log.info('Coinbase Sell Commit: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Sell Commit: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.buyRequest = function(token, accountId, data, cb) { - var data = { - amount: data.amount, - currency: data.currency, - payment_method: data.payment_method || null, - commit: false - }; - $http(_post('/accounts/' + accountId + '/buys', token, data)).then(function(data) { - $log.info('Coinbase Buy Request: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Buy Request: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.buyCommit = function(token, accountId, buyId, cb) { - $http(_post('/accounts/' + accountId + '/buys/' + buyId + '/commit', token)).then(function(data) { - $log.info('Coinbase Buy Commit: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Buy Commit: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.createAddress = function(token, accountId, data, cb) { - var data = { - name: data.name - }; - $http(_post('/accounts/' + accountId + '/addresses', token, data)).then(function(data) { - $log.info('Coinbase Create Address: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Create Address: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - root.sendTo = function(token, accountId, data, cb) { - var data = { - type: 'send', - to: data.to, - amount: data.amount, - currency: data.currency, - description: data.description - }; - $http(_post('/accounts/' + accountId + '/transactions', token, data)).then(function(data) { - $log.info('Coinbase Create Address: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Coinbase Create Address: ERROR ' + data.statusText); - return cb(data.data); - }); - }; - - // Pending transactions - - root.savePendingTransaction = function(ctx, opts, cb) { - var network = configService.getSync().coinbase.testnet ? 'testnet' : 'livenet'; - storageService.getCoinbaseTxs(network, function(err, oldTxs) { - if (lodash.isString(oldTxs)) { - oldTxs = JSON.parse(oldTxs); - } - if (lodash.isString(ctx)) { - ctx = JSON.parse(ctx); - } - var tx = oldTxs || {}; - tx[ctx.id] = ctx; - if (opts && (opts.error || opts.status)) { - tx[ctx.id] = lodash.assign(tx[ctx.id], opts); - } - if (opts && opts.remove) { - delete(tx[ctx.id]); - } - tx = JSON.stringify(tx); - - storageService.setCoinbaseTxs(network, tx, function(err) { - return cb(err); - }); - }); - }; - - root.getPendingTransactions = function(cb) { - var network = configService.getSync().coinbase.testnet ? 'testnet' : 'livenet'; - storageService.getCoinbaseTxs(network, function(err, txs) { - var _txs = txs ? JSON.parse(txs) : {}; - return cb(err, _txs); - }); - }; - - root.logout = function(network, cb) { - storageService.removeCoinbaseToken(network, function() { - storageService.removeCoinbaseRefreshToken(network, function() { - return cb(); - }); - }); - }; - - return root; - -}); - -'use strict'; - -angular.module('copayApp.services').factory('configService', function(storageService, lodash, $log) { - var root = {}; - - var defaultConfig = { - // wallet limits - limits: { - totalCopayers: 6, - mPlusN: 100, - }, - - // Bitcore wallet service URL - bws: { - url: 'https://bws.bitpay.com/bws/api', - }, - - // wallet default config - wallet: { - requiredCopayers: 2, - totalCopayers: 3, - spendUnconfirmed: false, - reconnectDelay: 5000, - idleDurationMin: 4, - settings: { - unitName: 'bits', - unitToSatoshi: 100, - unitDecimals: 2, - unitCode: 'bit', - alternativeName: 'US Dollar', - alternativeIsoCode: 'USD', - } - }, - - // External services - glidera: { - enabled: true, - testnet: false - }, - - coinbase: { - enabled: true, - testnet: false - }, - - rates: { - url: 'https://insight.bitpay.com:443/api/rates', - }, - - release: { - url: 'https://api.github.com/repos/bitpay/copay/releases/latest' - }, - - pushNotifications: { - enabled: true, - config: { - android: { - senderID: '1036948132229', - icon: 'push', - iconColor: '#2F4053' - }, - ios: { - alert: 'true', - badge: 'true', - sound: 'true', - }, - windows: {}, - } - }, - }; - - var configCache = null; - - - root.getSync = function() { - if (!configCache) - throw new Error('configService#getSync called when cache is not initialized'); - - return configCache; - }; - - root.get = function(cb) { - - storageService.getConfig(function(err, localConfig) { - if (localConfig) { - configCache = JSON.parse(localConfig); - - //these ifs are to avoid migration problems - if (!configCache.bws) { - configCache.bws = defaultConfig.bws; - } - if (!configCache.wallet) { - configCache.wallet = defaultConfig.wallet; - } - if (!configCache.wallet.settings.unitCode) { - configCache.wallet.settings.unitCode = defaultConfig.wallet.settings.unitCode; - } - if (!configCache.glidera) { - configCache.glidera = defaultConfig.glidera; - } - if (!configCache.coinbase) { - configCache.coinbase = defaultConfig.coinbase; - } - if (!configCache.pushNotifications) { - configCache.pushNotifications = defaultConfig.pushNotifications; - } - - } else { - configCache = lodash.clone(defaultConfig); - }; - - // Glidera - // Disabled for testnet - configCache.glidera.testnet = false; - - // Coinbase - // Disabled for testnet - configCache.coinbase.testnet = false; - - $log.debug('Preferences read:', configCache) - return cb(err, configCache); - }); - }; - - root.set = function(newOpts, cb) { - var config = lodash.cloneDeep(defaultConfig); - storageService.getConfig(function(err, oldOpts) { - oldOpts = oldOpts || {}; - - if (lodash.isString(oldOpts)) { - oldOpts = JSON.parse(oldOpts); - } - if (lodash.isString(config)) { - config = JSON.parse(config); - } - if (lodash.isString(newOpts)) { - newOpts = JSON.parse(newOpts); - } - - lodash.merge(config, oldOpts, newOpts); - configCache = config; - - storageService.storeConfig(JSON.stringify(config), cb); - }); - }; - - root.reset = function(cb) { - configCache = lodash.clone(defaultConfig); - storageService.removeConfig(cb); - }; - - root.getDefaults = function() { - return lodash.clone(defaultConfig); - }; - - - return root; -}); - - -'use strict'; - -angular.module('copayApp.services').factory('confirmDialog', function($log, $timeout, profileService, configService, gettextCatalog, platformInfo) { - var root = {}; - - - var acceptMsg = gettextCatalog.getString('Accept'); - var cancelMsg = gettextCatalog.getString('Cancel'); - var confirmMsg = gettextCatalog.getString('Confirm'); - - root.show = function(msg, cb) { - if (platformInfo.isCordova) { - navigator.notification.confirm( - msg, - function(buttonIndex) { - if (buttonIndex == 1) { - $timeout(function() { - return cb(true); - }, 1); - } else { - return cb(false); - } - }, - confirmMsg, [acceptMsg, cancelMsg] - ); - } else if (platformInfo.isChromeApp) { - // No feedback, alert/confirm not supported. - return cb(true); - } else { - return cb(confirm(msg)); - } - }; - - return root; -}); - - -'use strict'; - -angular.module('copayApp.services').factory('derivationPathHelper', function(lodash) { - var root = {}; - - root.default = "m/44'/0'/0'"; - root.defaultTestnet = "m/44'/1'/0'"; - - root.parse = function(str) { - var arr = str.split('/'); - - var ret = {}; - - if (arr[0] != 'm') - return false; - - switch (arr[1]) { - case "44'": - ret.derivationStrategy = 'BIP44'; - break; - case "45'": - return { - derivationStrategy: 'BIP45', - networkName: 'livenet', - account: 0, - } - break; - case "48'": - ret.derivationStrategy = 'BIP48'; - break; - default: - return false; - }; - - switch (arr[2]) { - case "0'": - ret.networkName = 'livenet'; - break; - case "1'": - ret.networkName = 'testnet'; - break; - default: - return false; - }; - - var match = arr[3].match(/(\d+)'/); - if (!match) - return false; - ret.account = +match[1] - - return ret; - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services').factory('feeService', function($log, bwcService, profileService, configService, gettext, lodash) { - var root = {}; - - // Constant fee options to translate - root.feeOpts = { - priority: gettext('Priority'), - normal: gettext('Normal'), - economy: gettext('Economy'), - superEconomy: gettext('Super Economy') - }; - - root.getCurrentFeeLevel = function() { - return configService.getSync().wallet.settings.feeLevel || 'normal'; - }; - - root.getCurrentFeeValue = function(cb) { - var fc = profileService.focusedClient; - var feeLevel = root.getCurrentFeeLevel(); - - fc.getFeeLevels(fc.credentials.network, function(err, levels) { - if (err) - return cb({ - message: 'Could not get dynamic fee' - }); - - var feeLevelValue = lodash.find(levels, { - level: feeLevel - }); - if (!feeLevelValue || !feeLevelValue.feePerKB) - return cb({ - message: 'Could not get dynamic fee for level: ' + feeLevel - }); - - var fee = feeLevelValue.feePerKB; - $log.debug('Dynamic fee: ' + feeLevel + ' ' + fee + ' SAT'); - return cb(null, fee); - }); - }; - - root.getFeeLevels = function(cb) { - var walletClient = bwcService.getClient(); - - var unitName = configService.getSync().wallet.settings.unitName; - - walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) { - walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) { - if (errLivenet || errTestnet) $log.debug('Could not get dynamic fee'); - else { - for (var i = 0; i < 4; i++) { - levelsLivenet[i]['feePerKBUnit'] = profileService.formatAmount(levelsLivenet[i].feePerKB) + ' ' + unitName; - levelsTestnet[i]['feePerKBUnit'] = profileService.formatAmount(levelsTestnet[i].feePerKB) + ' ' + unitName; - } - } - - return cb({ - 'livenet': levelsLivenet, - 'testnet': levelsTestnet - }); - }); - }); - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services') - .factory('fileStorageService', function(lodash, $log) { - var root = {}, - _fs, _dir; - - root.init = function(cb) { - if (_dir) return cb(null, _fs, _dir); - - function onFileSystemSuccess(fileSystem) { - console.log('File system started: ', fileSystem.name, fileSystem.root.name); - _fs = fileSystem; - root.getDir(function(err, newDir) { - if (err || !newDir.nativeURL) return cb(err); - _dir = newDir - $log.debug("Got main dir:", _dir.nativeURL); - return cb(null, _fs, _dir); - }); - } - - function fail(evt) { - var msg = 'Could not init file system: ' + evt.target.error.code; - console.log(msg); - return cb(msg); - }; - - window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, fail); - }; - - root.get = function(k, cb) { - root.init(function(err, fs, dir) { - if (err) return cb(err); - dir.getFile(k, { - create: false, - }, function(fileEntry) { - if (!fileEntry) return cb(); - fileEntry.file(function(file) { - var reader = new FileReader(); - - reader.onloadend = function(e) { - return cb(null, this.result) - } - - reader.readAsText(file); - }); - }, function(err) { - // Not found - if (err.code == 1) return cb(); - else return cb(err); - }); - }) - }; - - var writelock = {}; - - root.set = function(k, v, cb, delay) { - - delay = delay || 100; - - if (writelock[k]) { - return setTimeout(function() { - console.log('## Writelock for:' + k + ' Retrying in ' + delay); - return root.set(k, v, cb, delay + 100); - }, delay); - } - - writelock[k] = true; - root.init(function(err, fs, dir) { - if (err) { - writelock[k] = false; - return cb(err); - } - dir.getFile(k, { - create: true, - }, function(fileEntry) { - // Create a FileWriter object for our FileEntry (log.txt). - fileEntry.createWriter(function(fileWriter) { - - fileWriter.onwriteend = function(e) { - console.log('Write completed:' + k); - writelock[k] = false; - return cb(); - }; - - fileWriter.onerror = function(e) { - var err = e.error ? e.error : JSON.stringify(e); - console.log('Write failed: ' + err); - writelock[k] = false; - return cb('Fail to write:' + err); - }; - - if (lodash.isObject(v)) - v = JSON.stringify(v); - - if (!lodash.isString(v)) { - v = v.toString(); - } - - $log.debug('Writing:', k, v); - fileWriter.write(v); - - }, cb); - }); - }); - }; - - - // See https://github.com/apache/cordova-plugin-file/#where-to-store-files - root.getDir = function(cb) { - if (!cordova.file) { - return cb('Could not write on device storage'); - } - - var url = cordova.file.dataDirectory; - // This could be needed for windows - // if (cordova.file === undefined) { - // url = 'ms-appdata:///local/'; - window.resolveLocalFileSystemURL(url, function(dir) { - return cb(null, dir); - }, function(err) { - $log.warn(err); - return cb(err || 'Could not resolve filesystem:' + url); - }); - }; - - root.remove = function(k, cb) { - root.init(function(err, fs, dir) { - if (err) return cb(err); - dir.getFile(k, { - create: false, - }, function(fileEntry) { - // Create a FileWriter object for our FileEntry (log.txt). - fileEntry.remove(function() { - console.log('File removed.'); - return cb(); - }, cb); - }, cb); - }); - }; - - /** - * Same as setItem, but fails if an item already exists - */ - root.create = function(name, value, callback) { - root.get(name, - function(err, data) { - if (data) { - return callback('EEXISTS'); - } else { - return root.set(name, value, callback); - } - }); - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services').factory('fingerprintService', function($log, gettextCatalog, configService, platformInfo) { - var root = {}; - - var _isAvailable = false; - - if (platformInfo.isCordova && !platformInfo.isWP) { - window.plugins.touchid = window.plugins.touchid || {}; - window.plugins.touchid.isAvailable( - function(msg) { - _isAvailable = 'IOS'; - }, - function(msg) { - FingerprintAuth.isAvailable(function(result) { - - if (result.isAvailable) - _isAvailable = 'ANDROID'; - - }, function() { - _isAvailable = false; - }); - }); - }; - - var requestFinger = function(cb) { - try { - FingerprintAuth.show({ - clientId: 'Copay', - clientSecret: 'hVu1NvCZOyUuGgr46bFL', - }, - function(result) { - if (result.withFingerprint) { - $log.debug('Finger OK'); - return cb(); - } else if (result.withPassword) { - $log.debug("Finger: Authenticated with backup password"); - return cb(); - } - }, - function(msg) { - $log.debug('Finger Failed:' + JSON.stringify(msg)); - return cb(gettextCatalog.getString('Finger Scan Failed') + ': ' + msg.localizedDescription); - } - ); - } catch (e) { - $log.warn('Finger Scan Failed:' + JSON.stringify(e)); - return cb(gettextCatalog.getString('Finger Scan Failed')); - }; - }; - - - var requestTouchId = function(cb) { - try { - window.plugins.touchid.verifyFingerprint( - gettextCatalog.getString('Scan your fingerprint please'), - function(msg) { - $log.debug('Touch ID OK'); - return cb(); - }, - function(msg) { - $log.debug('Touch ID Failed:' + JSON.stringify(msg)); - return cb(gettextCatalog.getString('Touch ID Failed') + ': ' + msg.localizedDescription); - } - ); - } catch (e) { - $log.debug('Touch ID Failed:' + JSON.stringify(e)); - return cb(gettextCatalog.getString('Touch ID Failed')); - }; - }; - - var isNeeded = function(client) { - if (!_isAvailable) return false; - - var config = configService.getSync(); - config.touchIdFor = config.touchIdFor || {}; - - return config.touchIdFor[client.credentials.walletId]; - }; - - root.isAvailable = function(client) { - return _isAvailable; - }; - - root.check = function(client, cb) { - if (isNeeded(client)) { - $log.debug('FingerPrint Service:', _isAvailable); - if (_isAvailable == 'IOS') - return requestTouchId(cb); - else - return requestFinger(cb); - } else { - return cb(); - } - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services').factory('glideraService', function($http, $log, platformInfo) { - var root = {}; - var credentials = {}; - var isCordova = platformInfo.isCordova; - - root.setCredentials = function(network) { - if (network == 'testnet') { - credentials.HOST = 'https://sandbox.glidera.io'; - if (isCordova) { - credentials.REDIRECT_URI = 'copay://glidera'; - credentials.CLIENT_ID = '6163427a2f37d1b2022ececd6d6c9cdd'; - credentials.CLIENT_SECRET = '599cc3af26108c6fece8ab17c3f35867'; - } - else { - credentials.REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'; - credentials.CLIENT_ID = 'c402f4a753755456e8c384fb65b7be1d'; - credentials.CLIENT_SECRET = '3ce826198e3618d0b8ed341ab91fe4e5'; - } - } - else { - credentials.HOST = 'https://glidera.io'; - if (isCordova) { - credentials.REDIRECT_URI = 'copay://glidera'; - credentials.CLIENT_ID = '9c8023f0ac0128235b7b27a6f2610c83'; - credentials.CLIENT_SECRET = '30431511407b47f25a83bffd72881d55'; - } - else { - credentials.REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'; - credentials.CLIENT_ID = '8a9e8a9cf155db430c1ea6c7889afed1'; - credentials.CLIENT_SECRET = '24ddec578f38d5488bfe13601933c05f'; - } - }; - }; - - root.getOauthCodeUrl = function() { - return credentials.HOST - + '/oauth2/auth?response_type=code&client_id=' - + credentials.CLIENT_ID - + '&redirect_uri=' - + credentials.REDIRECT_URI; - }; - - root.getToken = function(code, cb) { - var req = { - method: 'POST', - url: credentials.HOST + '/api/v1/oauth/token', - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - data: { - grant_type : 'authorization_code', - code: code, - client_id : credentials.CLIENT_ID, - client_secret: credentials.CLIENT_SECRET, - redirect_uri: credentials.REDIRECT_URI - } - }; - - $http(req).then(function(data) { - $log.info('Glidera Authorization Access Token: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Authorization Access Token: ERROR ' + data.statusText); - return cb('Glidera Authorization Access Token: ERROR ' + data.statusText); - }); - }; - - var _get = function(endpoint, token) { - return { - method: 'GET', - url: credentials.HOST + '/api/v1' + endpoint, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - }; - }; - - root.getAccessTokenPermissions = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/oauth/token', token)).then(function(data) { - $log.info('Glidera Access Token Permissions: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Access Token Permissions: ERROR ' + data.statusText); - return cb('Glidera Access Token Permissions: ERROR ' + data.statusText); - }); - }; - - root.getEmail = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user/email', token)).then(function(data) { - $log.info('Glidera Get Email: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Get Email: ERROR ' + data.statusText); - return cb('Glidera Get Email: ERROR ' + data.statusText); - }); - }; - - root.getPersonalInfo = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user/personalinfo', token)).then(function(data) { - $log.info('Glidera Get Personal Info: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Get Personal Info: ERROR ' + data.statusText); - return cb('Glidera Get Personal Info: ERROR ' + data.statusText); - }); - }; - - root.getStatus = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user/status', token)).then(function(data) { - $log.info('Glidera User Status: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera User Status: ERROR ' + data.statusText); - return cb('Glidera User Status: ERROR ' + data.statusText); - }); - }; - - root.getLimits = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user/limits', token)).then(function(data) { - $log.info('Glidera Transaction Limits: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Transaction Limits: ERROR ' + data.statusText); - return cb('Glidera Transaction Limits: ERROR ' + data.statusText); - }); - }; - - root.getTransactions = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/transaction', token)).then(function(data) { - $log.info('Glidera Transactions: SUCCESS'); - return cb(null, data.data.transactions); - }, function(data) { - $log.error('Glidera Transactions: ERROR ' + data.statusText); - return cb('Glidera Transactions: ERROR ' + data.statusText); - }); - }; - - root.getTransaction = function(token, txid, cb) { - if (!token) return cb('Invalid Token'); - if (!txid) return cb('TxId required'); - $http(_get('/transaction/' + txid, token)).then(function(data) { - $log.info('Glidera Transaction: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Transaction: ERROR ' + data.statusText); - return cb('Glidera Transaction: ERROR ' + data.statusText); - }); - }; - - root.getSellAddress = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/user/create_sell_address', token)).then(function(data) { - $log.info('Glidera Create Sell Address: SUCCESS'); - return cb(null, data.data.sellAddress); - }, function(data) { - $log.error('Glidera Create Sell Address: ERROR ' + data.statusText); - return cb('Glidera Create Sell Address: ERROR ' + data.statusText); - }); - }; - - root.get2faCode = function(token, cb) { - if (!token) return cb('Invalid Token'); - $http(_get('/authentication/get2faCode', token)).then(function(data) { - $log.info('Glidera Sent 2FA code by SMS: SUCCESS'); - return cb(null, data.status == 200 ? true : false); - }, function(data) { - $log.error('Glidera Sent 2FA code by SMS: ERROR ' + data.statusText); - return cb('Glidera Sent 2FA code by SMS: ERROR ' + data.statusText); - }); - }; - - var _post = function(endpoint, token, twoFaCode, data) { - return { - method: 'POST', - url: credentials.HOST + '/api/v1' + endpoint, - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token, - '2FA_CODE': twoFaCode - }, - data: data - }; - }; - - root.sellPrice = function(token, price, cb) { - var data = { - qty: price.qty, - fiat: price.fiat - }; - $http(_post('/prices/sell', token, null, data)).then(function(data) { - $log.info('Glidera Sell Price: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Sell Price: ERROR ' + data.statusText); - return cb('Glidera Sell Price: ERROR ' + data.statusText); - }); - }; - - root.sell = function(token, twoFaCode, data, cb) { - var data = { - refundAddress: data.refundAddress, - signedTransaction: data.signedTransaction, - priceUuid: data.priceUuid, - useCurrentPrice: data.useCurrentPrice, - ip: data.ip - }; - $http(_post('/sell', token, twoFaCode, data)).then(function(data) { - $log.info('Glidera Sell: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Sell Request: ERROR ' + data.statusText); - return cb('Glidera Sell Request: ERROR ' + data.statusText); - }); - }; - - root.buyPrice = function(token, price, cb) { - var data = { - qty: price.qty, - fiat: price.fiat - }; - $http(_post('/prices/buy', token, null, data)).then(function(data) { - $log.info('Glidera Buy Price: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Buy Price: ERROR ' + data.statusText); - return cb('Glidera Buy Price: ERROR ' + data.statusText); - }); - }; - - root.buy = function(token, twoFaCode, data, cb) { - var data = { - destinationAddress: data.destinationAddress, - qty: data.qty, - priceUuid: data.priceUuid, - useCurrentPrice: data.useCurrentPrice, - ip: data.ip - }; - $http(_post('/buy', token, twoFaCode, data)).then(function(data) { - $log.info('Glidera Buy: SUCCESS'); - return cb(null, data.data); - }, function(data) { - $log.error('Glidera Buy Request: ERROR ' + data.statusText); - return cb('Glidera Buy Request: ERROR ' + data.statusText); - }); - }; - - return root; - -}); - -'use strict'; - -angular.module('copayApp.services').factory('go', function($window, $ionicSideMenuDelegate, $rootScope, $location, $state, $timeout, $log, profileService, platformInfo, nodeWebkit) { - var root = {}; - - root.openExternalLink = function(url, target) { - if (platformInfo.isNW) { - nodeWebkit.openExternalLink(url); - } else { - target = target || '_blank'; - var ref = window.open(url, target, 'location=no'); - } - }; - - root.is = function(name) { - return $state.is(name); - }; - - root.path = function(path, cb) { - $state.transitionTo(path) - .then(function() { - if (cb) return cb(); - }, function() { - if (cb) return cb('animation in progress'); - }); - }; - - root.toggleLeftMenu = function() { - $ionicSideMenuDelegate.toggleLeft(); - }; - - root.walletHome = function() { - var fc = profileService.focusedClient; - if (fc && !fc.isComplete()) { - $log.debug("Wallet not complete at startup... redirecting") - root.path('copayers'); - } else { - root.path('walletHome', function() { - $rootScope.$emit('Local/SetTab', 'walletHome', true); - }); - } - }; - - root.send = function() { - root.path('walletHome', function() { - $rootScope.$emit('Local/SetTab', 'send'); - }); - }; - - root.addWallet = function() { - $state.transitionTo('add'); - }; - - root.preferences = function() { - $state.transitionTo('preferences'); - }; - - root.preferencesGlobal = function() { - $state.transitionTo('preferencesGlobal'); - }; - - root.reload = function() { - $state.reload(); - }; - - - // Global go. This should be in a better place TODO - // We don't do a 'go' directive, to use the benefits of ng-touch with ng-click - $rootScope.go = function(path) { - root.path(path); - }; - - $rootScope.openExternalLink = function(url, target) { - root.openExternalLink(url, target); - }; - - - - return root; -}); - -'use strict'; -var logs = []; -angular.module('copayApp.services') - .factory('historicLog', function historicLog() { - var root = {}; - - root.add = function(level, msg) { - logs.push({ - level: level, - msg: msg, - }); - }; - - root.get = function() { - return logs; - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services') - .factory('hwWallet', function($log, bwcService) { - var root = {}; - - // Ledger magic number to get xPub without user confirmation - root.ENTROPY_INDEX_PATH = "0xb11e/"; - root.UNISIG_ROOTPATH = 44; - root.MULTISIG_ROOTPATH = 48; - root.LIVENET_PATH = 0; - - root._err = function(data) { - var msg = 'Hardware Wallet Error: ' + (data.error || data.message || 'unknown'); - $log.warn(msg); - return msg; - }; - - - root.getRootPath = function(device, isMultisig, account) { - if (!isMultisig) return root.UNISIG_ROOTPATH; - - // Compat - if (device == 'ledger' && account ==0) return root.UNISIG_ROOTPATH; - - return root.MULTISIG_ROOTPATH; - }; - - root.getAddressPath = function(device, isMultisig, account) { - return root.getRootPath(device,isMultisig,account) + "'/" + root.LIVENET_PATH + "'/" + account + "'"; - } - - root.getEntropyPath = function(device, isMultisig, account) { - var path; - - // Old ledger wallet compat - if (device == 'ledger' && account == 0) - return root.ENTROPY_INDEX_PATH + "0'"; - - return root.ENTROPY_INDEX_PATH + root.getRootPath(device,isMultisig,account) + "'/" + account + "'"; - }; - - root.pubKeyToEntropySource = function(xPubKey) { - var b = bwcService.getBitcore(); - var x = b.HDPublicKey(xPubKey); - return x.publicKey.toString(); - }; - - return root; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('latestReleaseService', function latestReleaseServiceFactory($log, $http, configService) { - - var root = {}; - - root.checkLatestRelease = function(cb) { - var releaseURL = configService.getDefaults().release.url; - - requestLatestRelease(releaseURL, function(err, release) { - if (err) return cb(err); - var currentVersion = window.version; - var latestVersion = release.data.tag_name; - - if (!verifyTagFormat(currentVersion)) - return cb('Cannot verify the format of version tag: ' + currentVersion); - if (!verifyTagFormat(latestVersion)) - return cb('Cannot verify the format of latest release tag: ' + latestVersion); - - var current = formatTagNumber(currentVersion); - var latest = formatTagNumber(latestVersion); - - if (latest.major < current.major || (latest.major == current.major && latest.minor <= current.minor)) - return cb(null, false); - - $log.debug('A new version of Copay is available: ' + latestVersion); - return cb(null, true); - }); - - function verifyTagFormat(tag) { - var regex = /^v?\d+\.\d+\.\d+$/i; - return regex.exec(tag); - }; - - function formatTagNumber(tag) { - var formattedNumber = tag.replace(/^v/i, '').split('.'); - return { - major: +formattedNumber[0], - minor: +formattedNumber[1], - patch: +formattedNumber[2] - }; - }; - }; - - function requestLatestRelease(releaseURL, cb) { - $log.debug('Retrieving latest relsease information...'); - - var request = { - url: releaseURL, - method: 'GET', - json: true - }; - - $http(request).then(function(release) { - $log.debug('Latest release: ' + release.data.name); - return cb(null, release); - }, function(err) { - return cb('Cannot get the release information: ' + err); - }); - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services') - .factory('ledger', function($log, bwcService, gettext, hwWallet) { - var root = {}; - var LEDGER_CHROME_ID = "kkdpmhnladdopljabkgpacgpliggeeaf"; - - root.callbacks = {}; - root.hasSession = function() { - root._message({ - command: "has_session" - }); - } - - root.getEntropySource = function(isMultisig, account, callback) { - root.getXPubKey(hwWallet.getEntropyPath('ledger', isMultisig, account), function(data) { - if (!data.success) - return callback(hwWallet._err(data)); - - return callback(null, hwWallet.pubKeyToEntropySource(data.xpubkey)); - }); - }; - - root.getXPubKey = function(path, callback) { - $log.debug('Ledger deriving xPub path:', path); - root.callbacks["get_xpubkey"] = callback; - root._messageAfterSession({ - command: "get_xpubkey", - path: path - }) - }; - - - root.getInfoForNewWallet = function(isMultisig, account, callback) { - var opts = {}; - root.getEntropySource(isMultisig, account, function(err, entropySource) { - if (err) return callback(err); - - opts.entropySource = entropySource; - root.getXPubKey(hwWallet.getAddressPath('ledger', isMultisig, account), function(data) { - if (!data.success) { - $log.warn(data.message); - return callback(data); - } - opts.extendedPublicKey = data.xpubkey; - opts.externalSource = 'ledger'; - opts.account = account; - - // Old ledger compat - opts.derivationStrategy = account ? 'BIP48' : 'BIP44'; - return callback(null, opts); - }); - }); - }; - - root._signP2SH = function(txp, account, isMultisig, callback) { - root.callbacks["sign_p2sh"] = callback; - var redeemScripts = []; - var paths = []; - var tx = bwcService.getUtils().buildTx(txp); - for (var i = 0; i < tx.inputs.length; i++) { - redeemScripts.push(new ByteString(tx.inputs[i].redeemScript.toBuffer().toString('hex'), GP.HEX).toString()); - paths.push(hwWallet.getAddressPath('ledger', isMultisig, account) + txp.inputs[i].path.substring(1)); - } - var splitTransaction = root._splitTransaction(new ByteString(tx.toString(), GP.HEX)); - var inputs = []; - for (var i = 0; i < splitTransaction.inputs.length; i++) { - var input = splitTransaction.inputs[i]; - inputs.push([ - root._reverseBytestring(input.prevout.bytes(0, 32)).toString(), - root._reverseBytestring(input.prevout.bytes(32)).toString() - ]); - } - $log.debug('Ledger signing paths:', paths); - root._messageAfterSession({ - command: "sign_p2sh", - inputs: inputs, - scripts: redeemScripts, - outputs_number: splitTransaction.outputs.length, - outputs_script: splitTransaction.outputScript.toString(), - paths: paths - }); - }; - - root.signTx = function(txp, account, callback) { - - // TODO Compat - var isMultisig = true; - if (txp.addressType == 'P2PKH') { - var msg = 'P2PKH wallets are not supported with ledger'; - $log.error(msg); - return callback(msg); - } else { - root._signP2SH(txp, account, isMultisig, callback); - } - } - - root._message = function(data) { - chrome.runtime.sendMessage( - LEDGER_CHROME_ID, { - request: data - }, - function(response) { - root._callback(response); - } - ); - } - - root._messageAfterSession = function(data) { - root._after_session = data; - root._message({ - command: "launch" - }); - root._should_poll_session = true; - root._do_poll_session(); - } - - root._do_poll_session = function() { - root.hasSession(); - if (root._should_poll_session) { - setTimeout(root._do_poll_session, 500); - } - } - - root._callback = function(data) { - if (typeof data == "object") { - if (data.command == "has_session" && data.success) { - root._message(root._after_session); - root._after_session = null; - root._should_poll_session = false; - } else if (typeof root.callbacks[data.command] == "function") { - root.callbacks[data.command](data); - } - } else { - root._should_poll_session = false; - Object.keys(root.callbacks).forEach(function(key) { - root.callbacks[key]({ - success: false, - message: gettext("The Ledger Chrome application is not installed"), - }); - }); - } - } - - root._splitTransaction = function(transaction) { - var result = {}; - var inputs = []; - var outputs = []; - var offset = 0; - var version = transaction.bytes(offset, 4); - offset += 4; - var varint = root._getVarint(transaction, offset); - var numberInputs = varint[0]; - offset += varint[1]; - for (var i = 0; i < numberInputs; i++) { - var input = {}; - input['prevout'] = transaction.bytes(offset, 36); - offset += 36; - varint = root._getVarint(transaction, offset); - offset += varint[1]; - input['script'] = transaction.bytes(offset, varint[0]); - offset += varint[0]; - input['sequence'] = transaction.bytes(offset, 4); - offset += 4; - inputs.push(input); - } - varint = root._getVarint(transaction, offset); - var numberOutputs = varint[0]; - offset += varint[1]; - var outputStartOffset = offset; - for (var i = 0; i < numberOutputs; i++) { - var output = {}; - output['amount'] = transaction.bytes(offset, 8); - offset += 8; - varint = root._getVarint(transaction, offset); - offset += varint[1]; - output['script'] = transaction.bytes(offset, varint[0]); - offset += varint[0]; - outputs.push(output); - } - var locktime = transaction.bytes(offset, 4); - result['version'] = version; - result['inputs'] = inputs; - result['outputs'] = outputs; - result['locktime'] = locktime; - result['outputScript'] = transaction.bytes(outputStartOffset, offset - outputStartOffset); - return result; - } - - root._getVarint = function(data, offset) { - if (data.byteAt(offset) < 0xfd) { - return [data.byteAt(offset), 1]; - } - if (data.byteAt(offset) == 0xfd) { - return [((data.byteAt(offset + 2) << 8) + data.byteAt(offset + 1)), 3]; - } - if (data.byteAt(offset) == 0xfe) { - return [((data.byteAt(offset + 4) << 24) + (data.byteAt(offset + 3) << 16) + - (data.byteAt(offset + 2) << 8) + data.byteAt(offset + 1)), 5]; - } - } - - root._reverseBytestring = function(x) { - var res = ""; - for (var i = x.length - 1; i >= 0; i--) { - res += Convert.toHexByte(x.byteAt(i)); - } - return new ByteString(res, GP.HEX); - } - - return root; - }); - -var Convert = {}; - -/** - * Convert a binary string to his hexadecimal representation - * @param {String} src binary string - * @static - * @returns {String} hexadecimal representation - */ -Convert.stringToHex = function(src) { - var r = ""; - var hexes = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"); - for (var i = 0; i < src.length; i++) { - r += hexes[src.charCodeAt(i) >> 4] + hexes[src.charCodeAt(i) & 0xf]; - } - return r; -} - -/** - * Convert an hexadecimal string to its binary representation - * @param {String} src hexadecimal string - * @static - * @return {Array} byte array - * @throws {InvalidString} if the string isn't properly formatted - */ -Convert.hexToBin = function(src) { - var result = ""; - var digits = "0123456789ABCDEF"; - if ((src.length % 2) != 0) { - throw "Invalid string"; - } - src = src.toUpperCase(); - for (var i = 0; i < src.length; i += 2) { - var x1 = digits.indexOf(src.charAt(i)); - if (x1 < 0) { - return ""; - } - var x2 = digits.indexOf(src.charAt(i + 1)); - if (x2 < 0) { - return ""; - } - result += String.fromCharCode((x1 << 4) + x2); - } - return result; -} - -/** - * Convert a double digit hexadecimal number to an integer - * @static - * @param {String} data buffer containing the digit to parse - * @param {Number} offset offset to the digit (default is 0) - * @returns {Number} converted digit - */ -Convert.readHexDigit = function(data, offset) { - var digits = '0123456789ABCDEF'; - if (typeof offset == "undefined") { - offset = 0; - } - return (digits.indexOf(data.substring(offset, offset + 1).toUpperCase()) << 4) + (digits.indexOf(data.substring(offset + 1, offset + 2).toUpperCase())); -} - -/** - * Convert a number to a two digits hexadecimal string (deprecated) - * @static - * @param {Number} number number to convert - * @returns {String} converted number - */ -Convert.toHexDigit = function(number) { - var digits = '0123456789abcdef'; - return digits.charAt(number >> 4) + digits.charAt(number & 0x0F); -} - -/** - * Convert a number to a two digits hexadecimal string (similar to toHexDigit) - * @static - * @param {Number} number number to convert - * @returns {String} converted number - */ -Convert.toHexByte = function(number) { - return Convert.toHexDigit(number); -} - -/** - * Convert a BCD number to a two digits hexadecimal string - * @static - * @param {Number} number number to convert - * @returns {String} converted number - */ -Convert.toHexByteBCD = function(numberBCD) { - var number = ((numberBCD / 10) * 16) + (numberBCD % 10); - return Convert.toHexDigit(number); -} - - -/** - * Convert a number to an hexadecimal short number - * @static - * @param {Number} number number to convert - * @returns {String} converted number - */ -Convert.toHexShort = function(number) { - return Convert.toHexDigit((number >> 8) & 0xff) + Convert.toHexDigit(number & 0xff); -} - -/** - * Convert a number to an hexadecimal int number - * @static - * @param {Number} number number to convert - * @returns {String} converted number - */ -Convert.toHexInt = function(number) { - return Convert.toHexDigit((number >> 24) & 0xff) + Convert.toHexDigit((number >> 16) & 0xff) + - Convert.toHexDigit((number >> 8) & 0xff) + Convert.toHexDigit(number & 0xff); -} - - -var GP = {}; -GP.ASCII = 1; -GP.HEX = 5; - -/** - * @class GPScript ByteString implementation - * @param {String} value initial value - * @param {HEX|ASCII} encoding encoding to use - * @property {Number} length length of the ByteString - * @constructs - */ -var ByteString = function(value, encoding) { - this.encoding = encoding; - this.hasBuffer = (typeof Buffer != 'undefined'); - if (this.hasBuffer && (value instanceof Buffer)) { - this.value = value; - this.encoding = GP.HEX; - } else { - switch (encoding) { - case GP.HEX: - if (!this.hasBuffer) { - this.value = Convert.hexToBin(value); - } else { - this.value = new Buffer(value, 'hex'); - } - break; - - case GP.ASCII: - if (!this.hasBuffer) { - this.value = value; - } else { - this.value = new Buffer(value, 'ascii'); - } - break; - - default: - throw "Invalid arguments"; - } - } - this.length = this.value.length; -} - -/** - * Retrieve the byte value at the given index - * @param {Number} index index - * @returns {Number} byte value - */ -ByteString.prototype.byteAt = function(index) { - if (arguments.length < 1) { - throw "Argument missing"; - } - if (typeof index != "number") { - throw "Invalid index"; - } - if ((index < 0) || (index >= this.value.length)) { - throw "Invalid index offset"; - } - if (!this.hasBuffer) { - return Convert.readHexDigit(Convert.stringToHex(this.value.substring(index, index + 1))); - } else { - return this.value[index]; - } -} - -/** - * Retrieve a subset of the ByteString - * @param {Number} offset offset to start at - * @param {Number} [count] size of the target ByteString (default : use the remaining length) - * @returns {ByteString} subset of the original ByteString - */ -ByteString.prototype.bytes = function(offset, count) { - var result; - if (arguments.length < 1) { - throw "Argument missing"; - } - if (typeof offset != "number") { - throw "Invalid offset"; - } - //if ((offset < 0) || (offset >= this.value.length)) { - if (offset < 0) { - throw "Invalid offset"; - } - if (typeof count == "number") { - if (count < 0) { - throw "Invalid count"; - } - if (!this.hasBuffer) { - result = new ByteString(this.value.substring(offset, offset + count), GP.ASCII); - } else { - result = new Buffer(count); - this.value.copy(result, 0, offset, offset + count); - } - } else - if (typeof count == "undefined") { - if (!this.hasBuffer) { - result = new ByteString(this.value.substring(offset), GP.ASCII); - } else { - result = new Buffer(this.value.length - offset); - this.value.copy(result, 0, offset, this.value.length); - } - } else { - throw "Invalid count"; - } - if (!this.hasBuffer) { - result.encoding = this.encoding; - return result; - } else { - return new ByteString(result, GP.HEX); - } -} - -/** - * Appends two ByteString - * @param {ByteString} target ByteString to append - * @returns {ByteString} result of the concatenation - */ -ByteString.prototype.concat = function(target) { - if (arguments.length < 1) { - throw "Not enough arguments"; - } - if (!(target instanceof ByteString)) { - throw "Invalid argument"; - } - if (!this.hasBuffer) { - var result = this.value + target.value; - var x = new ByteString(result, GP.ASCII); - x.encoding = this.encoding; - return x; - } else { - var result = Buffer.concat([this.value, target.value]); - return new ByteString(result, GP.HEX); - } -} - -/** - * Check if two ByteString are equal - * @param {ByteString} target ByteString to check against - * @returns {Boolean} true if the two ByteString are equal - */ -ByteString.prototype.equals = function(target) { - if (arguments.length < 1) { - throw "Not enough arguments"; - } - if (!(target instanceof ByteString)) { - throw "Invalid argument"; - } - if (!this.hasBuffer) { - return (this.value == target.value); - } else { - return Buffer.equals(this.value, target.value); - } -} - - -/** - * Convert the ByteString to a String using the given encoding - * @param {HEX|ASCII|UTF8|BASE64|CN} encoding encoding to use - * @return {String} converted content - */ -ByteString.prototype.toString = function(encoding) { - var targetEncoding = this.encoding; - if (arguments.length >= 1) { - if (typeof encoding != "number") { - throw "Invalid encoding"; - } - switch (encoding) { - case GP.HEX: - case GP.ASCII: - targetEncoding = encoding; - break; - - default: - throw "Unsupported arguments"; - } - targetEncoding = encoding; - } - switch (targetEncoding) { - case GP.HEX: - if (!this.hasBuffer) { - return Convert.stringToHex(this.value); - } else { - return this.value.toString('hex'); - } - case GP.ASCII: - if (!this.hasBuffer) { - return this.value; - } else { - return this.value.toString(); - } - default: - throw "Unsupported"; - } -} - -ByteString.prototype.toStringIE = function(encoding) { - return this.toString(encoding); -} - -ByteString.prototype.toBuffer = function() { - return this.value; -} - -'use strict'; - -angular.module('copayApp.services') - .factory('localStorageService', function(platformInfo, $timeout, $log) { - var isNW = platformInfo.isNW; - var isChromeApp = platformInfo.isChromeApp; - var root = {}; - var ls = ((typeof window.localStorage !== "undefined") ? window.localStorage : null); - - if (isChromeApp && !isNW && !ls) { - $log.info('Using CHROME storage'); - ls = chrome.storage.local; - } - - - if (!ls) - throw new Error('localstorage not available'); - - root.get = function(k, cb) { - if (isChromeApp || isNW) { - chrome.storage.local.get(k, - function(data) { - //TODO check for errors - return cb(null, data[k]); - }); - } else { - return cb(null, ls.getItem(k)); - } - }; - - /** - * Same as setItem, but fails if an item already exists - */ - root.create = function(name, value, callback) { - root.get(name, - function(err, data) { - if (data) { - return callback('EEXISTS'); - } else { - return root.set(name, value, callback); - } - }); - }; - - root.set = function(k, v, cb) { - if (isChromeApp || isNW) { - var obj = {}; - obj[k] = v; - - chrome.storage.local.set(obj, cb); - } else { - ls.setItem(k, v); - return cb(); - } - - }; - - root.remove = function(k, cb) { - if (isChromeApp || isNW) { - chrome.storage.local.remove(k, cb); - } else { - ls.removeItem(k); - return cb(); - } - - }; - - - if (isNW) { - $log.info('Overwritting localstorage with chrome storage for NW.JS'); - - var ts = ls.getItem('migrationToChromeStorage'); - var p = ls.getItem('profile'); - - // Need migration? - if (!ts && p) { - $log.info('### MIGRATING DATA! TO CHROME STORAGE'); - - var j = 0; - for (var i = 0; i < localStorage.length; i++) { - var k = ls.key(i); - var v = ls.getItem(k); - - $log.debug(' Key: ' + k); - root.set(k, v, function() { - j++; - if (j == localStorage.length) { - $log.info('### MIGRATION DONE'); - ls.setItem('migrationToChromeStorage', Date.now()) - ls = chrome.storage.local; - } - }) - } - } else if (p) { - $log.info('# Data already migrated to Chrome storage on ' + ts); - } - } - - - return root; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('logHeader', function($log, platformInfo) { - $log.info('Starting Copay v' + window.version + ' #' + window.commitHash); - $log.info('Client: '+ JSON.stringify(platformInfo) ); - return {}; - }); - -'use strict'; - -angular.module('copayApp.services').factory('nodeWebkit', function nodeWebkitFactory() { - var root = {}; - - var isNodeWebkit = function() { - var isNode = (typeof process !== "undefined" && typeof require !== "undefined"); - if(isNode) { - try { - return (typeof require('nw.gui') !== "undefined"); - } catch(e) { - return false; - } - } - }; - - root.readFromClipboard = function() { - if (!isNodeWebkit()) return; - var gui = require('nw.gui'); - var clipboard = gui.Clipboard.get(); - return clipboard.get(); - }; - - root.writeToClipboard = function(text) { - if (!isNodeWebkit()) return; - var gui = require('nw.gui'); - var clipboard = gui.Clipboard.get(); - return clipboard.set(text); - }; - - root.openExternalLink = function(url) { - if (!isNodeWebkit()) return; - var gui = require('nw.gui'); - return gui.Shell.openExternal(url); - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services'). -factory('notification', function($timeout, platformInfo) { - - var isCordova = platformInfo.isCordova; - var notifications = []; - - /* - ls.getItem('notifications', function(err, data) { - if (data) { - notifications = JSON.parse(data); - } - }); - */ - - var queue = []; - var settings = { - info: { - duration: 6000, - enabled: true - }, - funds: { - duration: 7000, - enabled: true - }, - version: { - duration: 60000, - enabled: true - }, - warning: { - duration: 7000, - enabled: true - }, - error: { - duration: 7000, - enabled: true - }, - success: { - duration: 5000, - enabled: true - }, - progress: { - duration: 0, - enabled: true - }, - custom: { - duration: 35000, - enabled: true - }, - details: true, - localStorage: false, - html5Mode: false, - html5DefaultIcon: 'img/favicon.ico' - }; - - function html5Notify(icon, title, content, ondisplay, onclose) { - if (window.webkitNotifications && window.webkitNotifications.checkPermission() === 0) { - if (!icon) { - icon = 'img/favicon.ico'; - } - var noti = window.webkitNotifications.createNotification(icon, title, content); - if (typeof ondisplay === 'function') { - noti.ondisplay = ondisplay; - } - if (typeof onclose === 'function') { - noti.onclose = onclose; - } - noti.show(); - } else { - settings.html5Mode = false; - } - } - - - return { - - /* ========== SETTINGS RELATED METHODS =============*/ - - disableHtml5Mode: function() { - settings.html5Mode = false; - }, - - disableType: function(notificationType) { - settings[notificationType].enabled = false; - }, - - enableHtml5Mode: function() { - // settings.html5Mode = true; - settings.html5Mode = this.requestHtml5ModePermissions(); - }, - - enableType: function(notificationType) { - settings[notificationType].enabled = true; - }, - - getSettings: function() { - return settings; - }, - - toggleType: function(notificationType) { - settings[notificationType].enabled = !settings[notificationType].enabled; - }, - - toggleHtml5Mode: function() { - settings.html5Mode = !settings.html5Mode; - }, - - requestHtml5ModePermissions: function() { - if (window.webkitNotifications) { - if (window.webkitNotifications.checkPermission() === 0) { - return true; - } else { - window.webkitNotifications.requestPermission(function() { - if (window.webkitNotifications.checkPermission() === 0) { - settings.html5Mode = true; - } else { - settings.html5Mode = false; - } - }); - return false; - } - } else { - return false; - } - }, - - - /* ============ QUERYING RELATED METHODS ============*/ - - getAll: function() { - // Returns all notifications that are currently stored - return notifications; - }, - - getQueue: function() { - return queue; - }, - - /* ============== NOTIFICATION METHODS ==============*/ - - info: function(title, content, userData) { - return this.awesomeNotify('info', 'fi-info', title, content, userData); - }, - - funds: function(title, content, userData) { - return this.awesomeNotify('funds', 'icon-receive', title, content, userData); - }, - - version: function(title, content, severe) { - return this.awesomeNotify('version', severe ? 'fi-alert' : 'fi-flag', title, content); - }, - - error: function(title, content, userData) { - return this.awesomeNotify('error', 'fi-x', title, content, userData); - }, - - success: function(title, content, userData) { - return this.awesomeNotify('success', 'fi-check', title, content, userData); - }, - - warning: function(title, content, userData) { - return this.awesomeNotify('warning', 'fi-alert', title, content, userData); - }, - - new: function(title, content, userData) { - return this.awesomeNotify('warning', 'fi-plus', title, content, userData); - }, - - sent: function(title, content, userData) { - return this.awesomeNotify('warning', 'icon-paperplane', title, content, userData); - }, - - awesomeNotify: function(type, icon, title, content, userData) { - /** - * Supposed to wrap the makeNotification method for drawing icons using font-awesome - * rather than an image. - * - * Need to find out how I'm going to make the API take either an image - * resource, or a font-awesome icon and then display either of them. - * Also should probably provide some bits of color, could do the coloring - * through classes. - */ - // image = ''; - return this.makeNotification(type, false, icon, title, content, userData); - }, - - notify: function(image, title, content, userData) { - // Wraps the makeNotification method for displaying notifications with images - // rather than icons - return this.makeNotification('custom', image, true, title, content, userData); - }, - - makeNotification: function(type, image, icon, title, content, userData) { - var notification = { - 'type': type, - 'image': image, - 'icon': icon, - 'title': title, - 'content': content, - 'timestamp': +new Date(), - 'userData': userData - }; - - notifications.push(notification); - - if (settings.html5Mode) { - html5Notify(image, title, content, function() { - // inner on display function - }, function() { - // inner on close function - }); - } - - //this is done because html5Notify() changes the variable settings.html5Mode - if (!settings.html5Mode) { - queue.push(notification); - $timeout(function removeFromQueueTimeout() { - queue.splice(queue.indexOf(notification), 1); - }, settings[type].duration); - } - - // Mobile notification - if (window && window.navigator && window.navigator.vibrate) { - window.navigator.vibrate([200, 100, 200]); - }; - - if (document.hidden && (type == 'info' || type == 'funds') && !isCordova) { - new window.Notification(title, { - body: content, - icon: 'img/notification.png' - }); - } - - this.save(); - return notification; - }, - - - /* ============ PERSISTENCE METHODS ============ */ - - save: function() { - // Save all the notifications into localStorage - if (settings.localStorage) { - localStorage.setItem('notifications', JSON.stringify(notifications)); - } - }, - - restore: function() { - // Load all notifications from localStorage - }, - - clear: function() { - notifications = []; - this.save(); - } - - }; - } -).directive('notifications', function(notification, $compile) { - /** - * - * It should also parse the arguments passed to it that specify - * its position on the screen like "bottom right" and apply those - * positions as a class to the container element - * - * Finally, the directive should have its own controller for - * handling all of the notifications from the notification service - */ - function link(scope, element, attrs) { - var position = attrs.notifications; - position = position.split(' '); - element.addClass('dr-notification-container'); - for (var i = 0; i < position.length; i++) { - element.addClass(position[i]); - } - } - - return { - restrict: 'A', - scope: {}, - templateUrl: 'views/includes/notifications.html', - link: link, - controller: ['$scope', - function NotificationsCtrl($scope) { - $scope.queue = notification.getQueue(); - - $scope.removeNotification = function(noti) { - $scope.queue.splice($scope.queue.indexOf(noti), 1); - }; - } - ] - - }; -}); - -'use strict'; -angular.module('copayApp.services') - .factory('notificationService', function profileServiceFactory($filter, notification, lodash, configService, gettext) { - - var root = {}; - - var groupingTime = 5000; - var lastNotificationOnWallet = {}; - - root.getLast = function(walletId) { - var last = lastNotificationOnWallet[walletId]; - if (!last) return null; - - return Date.now() - last.ts < groupingTime ? last : null; - }; - - root.storeLast = function(notificationData, walletId) { - - if (notificationData.type == 'NewAddress') - return; - - lastNotificationOnWallet[walletId] = { - creatorId: notificationData.creatorId, - type: notificationData.type, - ts: Date.now(), - }; - }; - - root.shouldSkip = function(notificationData, last) { - if (!last) return false; - - // rules... - if (last.type === 'NewTxProposal' && - notificationData.type === 'TxProposalAcceptedBy') - return true; - - if (last.type === 'TxProposalFinallyAccepted' && - notificationData.type === 'NewOutgoingTx') - return true; - - if (last.type === 'TxProposalRejectedBy' && - notificationData.type === 'TxProposalFinallyRejected') - return true; - - return false; - }; - - - root.newBWCNotification = function(notificationData, walletId, walletName) { - var last = root.getLast(walletId); - root.storeLast(notificationData, walletId); - - if (root.shouldSkip(notificationData, last)) - return; - - var config = configService.getSync(); - config.colorFor = config.colorFor || {}; - var color = config.colorFor[walletId] || '#4A90E2'; - var name = config.aliasFor[walletId] || walletName; - - switch (notificationData.type) { - case 'NewTxProposal': - notification.new(gettext('New Payment Proposal'), - name, { - color: color - }); - break; - case 'TxProposalAcceptedBy': - notification.success(gettext('Payment Proposal Signed by Copayer'), - name, { - color: color - }); - break; - case 'TxProposalRejectedBy': - notification.error(gettext('Payment Proposal Rejected by Copayer'), - name, { - color: color - }); - break; - case 'TxProposalFinallyRejected': - notification.error(gettext('Payment Proposal Rejected'), - name, { - color: color - }); - break; - case 'NewOutgoingTx': - notification.sent(gettext('Payment Sent'), - name, { - color: color - }); - break; - case 'NewIncomingTx': - notification.funds(gettext('Funds received'), - name, { - color: color - }); - break; - case 'ScanFinished': - notification.success(gettext('Scan Finished'), - name, { - color: color - }); - break; - - case 'NewCopayer': - // No UX notification - break; - case 'BalanceUpdated': - // No UX notification - break; - } - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services').factory('ongoingProcess', function($log, $timeout, $filter, lodash, $ionicLoading, gettext, platformInfo) { - var root = {}; - var isCordova = platformInfo.isCordova; - - var ongoingProcess = {}; - - var processNames = { - 'scanning': gettext('Scanning Wallet funds...'), - 'recreating': gettext('Recreating Wallet...'), - 'generatingCSV': gettext('Generating .csv file...'), - 'creatingTx': gettext('Creating transaction'), - 'sendingTx': gettext('Sending transaction'), - 'signingTx': gettext('Signing transaction'), - 'broadcastingTx': gettext('Broadcasting transaction'), - 'fetchingPayPro': gettext('Fetching Payment Information'), - 'calculatingFee': gettext('Calculating fee'), - 'joiningWallet': gettext('Joining Wallet...'), - 'retrivingInputs': gettext('Retrieving inputs information'), - 'creatingWallet': gettext('Creating Wallet...'), - 'validatingWallet': gettext('Validating wallet integrity...'), - 'connectingledger': gettext('Waiting for Ledger...'), - 'connectingtrezor': gettext('Waiting for Trezor...'), - 'validatingWords': gettext('Validating recovery phrase...'), - 'connectingCoinbase': gettext('Connecting to Coinbase...'), - 'connectingGlidera': gettext('Connecting to Glidera...'), - 'importingWallet': gettext('Importing Wallet...'), - 'sweepingWallet': gettext('Sweeping Wallet...'), - 'deletingWallet': gettext('Deleting Wallet...'), - 'extractingWalletInfo': gettext('Extracting Wallet Information...'), - }; - - root.clear = function() { - ongoingProcess = {}; - if (isCordova) { - window.plugins.spinnerDialog.hide(); - } else { - $ionicLoading.hide(); - } - }; - - root.get = function(processName) { - return ongoingProcess[processName]; - }; - - root.set = function(processName, isOn) { - $log.debug('ongoingProcess', processName, isOn); - root[processName] = isOn; - ongoingProcess[processName] = isOn; - - var name; - root.any = lodash.any(ongoingProcess, function(isOn, processName) { - if (isOn) - name = name || processName; - return isOn; - }); - // The first one - root.onGoingProcessName = name; - - var showName = $filter('translate')(processNames[name] || name); - - if (root.onGoingProcessName) { - if (isCordova) { - window.plugins.spinnerDialog.show(null, showName, true); - } else { - - var tmpl = '' + showName; - $ionicLoading.show({ - template: tmpl - }); - } - } else { - if (isCordova) { - window.plugins.spinnerDialog.hide(); - } else { - $ionicLoading.hide(); - } - } - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services').factory('openURLService', function($rootScope, $ionicHistory, $document, $log, $state, go, platformInfo, lodash, profileService) { - var root = {}; - - root.registeredUriHandlers = [{ - name: 'Bitcoin BIP21 URL', - startsWith: 'bitcoin:', - transitionTo: 'uripayment', - }, { - name: 'Glidera Authentication Callback', - startsWith: 'copay:glidera', - transitionTo: 'uriglidera', - }, { - name: 'Coinbase Authentication Callback', - startsWith: 'copay:coinbase', - transitionTo: 'uricoinbase', - }]; - - - var handleOpenURL = function(args) { - $log.info('Handling Open URL: ' + JSON.stringify(args)); - - if (!profileService.isBound) { - $log.warn('Profile not bound yet. Waiting'); - - return $rootScope.$on('Local/ProfileBound', function() { - // Wait ux to settle - setTimeout(function() { - $log.warn('Profile ready, retrying...'); - handleOpenURL(args); - }, 2000); - }); - }; - - // Stop it from caching the first view as one to return when the app opens - $ionicHistory.nextViewOptions({ - historyRoot: true, - disableBack: true, - disableAnimation: true - }); - var url = args.url; - if (!url) { - $log.error('No url provided'); - return; - }; - - if (url) { - if ('cordova' in window) { - window.cordova.removeDocumentEventHandler('handleopenurl'); - window.cordova.addStickyDocumentEventHandler('handleopenurl'); - } - document.removeEventListener('handleopenurl', handleOpenURL); - } - - document.addEventListener('handleopenurl', handleOpenURL, false); - - var x = lodash.find(root.registeredUriHandlers, function(x) { - return url.indexOf(x.startsWith) == 0 || - url.indexOf('web+' + x.startsWith) == 0 || // web protocols - url.indexOf(x.startsWith.replace(':', '://')) == 0 // from mobile devices - ; - }); - - if (x) { - $log.debug('openURL GOT ' + x.name + ' URL'); - return $state.transitionTo(x.transitionTo, { - url: url - }); - } else { - $log.warn('Unknown URL! : ' + url); - } - }; - - var handleResume = function() { - $log.debug('Handle Resume @ openURL...'); - document.addEventListener('handleopenurl', handleOpenURL, false); - }; - - root.init = function() { - $log.debug('Initializing openURL'); - document.addEventListener('handleopenurl', handleOpenURL, false); - document.addEventListener('resume', handleResume, false); - - if (platformInfo.isChromeApp) { - $log.debug('Registering Chrome message listener'); - chrome.runtime.onMessage.addListener( - function(request, sender, sendResponse) { - if (request.url) { - handleOpenURL(request.url); - } - }); - } else if (platformInfo.isNW) { - var gui = require('nw.gui'); - - // This event is sent to an existent instance of Copay (only for standalone apps) - gui.App.on('open', function(pathData) { - if (pathData.indexOf('bitcoin:') != -1) { - $log.debug('Bitcoin URL found'); - handleOpenURL({ - url: pathData.substring(pathData.indexOf('bitcoin:')) - }); - } else if (pathData.indexOf('copay:') != -1) { - $log.debug('Copay URL found'); - handleOpenURL({ - url: pathData.substring(pathData.indexOf('copay:')) - }); - } - }); - - // Used at the startup of Copay - var argv = gui.App.argv; - if (argv && argv[0]) { - handleOpenURL({ - url: argv[0] - }); - } - } else if (platformInfo.isDevel) { - - var base = window.location.origin + '/'; - var url = base + '#/uri/%s'; - - if (navigator.registerProtocolHandler) { - $log.debug('Registering Browser handlers base:' + base); - navigator.registerProtocolHandler('bitcoin', url, 'Copay Bitcoin Handler'); - navigator.registerProtocolHandler('web+copay', url, 'Copay Wallet Handler'); - } - } - }; - - root.registerHandler = function(x) { - $log.debug('Registering URL Handler: ' + x.name); - root.registeredUriHandlers.push(x); - }; - - root.handleURL = handleOpenURL; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services').factory('platformInfo', function($window) { - - var ua = navigator ? navigator.userAgent : null; - - if (!ua) { - console.log('Could not determine navigator. Using fixed string'); - ua = 'dummy user-agent'; - } - - // Fixes IOS WebKit UA - ua = ua.replace(/\(\d+\)$/, ''); - - var isNodeWebkit = function() { - var isNode = (typeof process !== "undefined" && typeof require !== "undefined"); - if (isNode) { - try { - return (typeof require('nw.gui') !== "undefined"); - } catch (e) { - return false; - } - } - }; - - - // Detect mobile devices - var ret = { - isAndroid: !!ua.match(/Android/i), - isIOS: /iPad|iPhone|iPod/.test(ua) && !$window.MSStream, - isWP: !!ua.match(/IEMobile/i), - isSafari: Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0, - ua: ua, - isCordova: !!$window.cordova, - isNW: isNodeWebkit(), - }; - - ret.isMobile = ret.isAndroid || ret.isIOS || ret.isWP; - ret.isChromeApp = $window.chrome && chrome.runtime && chrome.runtime.id && !ret.isNW; - ret.isDevel = !ret.isMobile && !ret.isChromeApp && !ret.isNW; - - return ret; -}); - -'use strict'; -angular.module('copayApp.services') - .factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, notificationService, pushNotificationsService, gettext, gettextCatalog, bwcError, uxLanguage, bitcore, platformInfo, walletService) { - - - var isChromeApp = platformInfo.isChromeApp; - var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; - var isIOS = platformInfo.isIOS; - - var root = {}; - var errors = bwcService.getErrors(); - var usePushNotifications = isCordova && !isWP; - - var FOREGROUND_UPDATE_PERIOD = 5; - var BACKGROUND_UPDATE_PERIOD = 30; - - root.profile = null; - root.focusedClient = null; - root.walletClients = {}; - - root.Utils = bwcService.getUtils(); - root.formatAmount = function(amount, fullPrecision) { - var config = configService.getSync().wallet.settings; - if (config.unitCode == 'sat') return amount; - - //TODO : now only works for english, specify opts to change thousand separator and decimal separator - var opts = { - fullPrecision: !!fullPrecision - }; - return this.Utils.formatAmount(amount, config.unitCode, opts); - }; - - root._setFocus = function(walletId, cb) { - $log.debug('Set focus:', walletId); - - // Set local object - if (walletId) - root.focusedClient = root.walletClients[walletId]; - else - root.focusedClient = []; - - if (lodash.isEmpty(root.focusedClient)) { - root.focusedClient = root.walletClients[lodash.keys(root.walletClients)[0]]; - } - - // Still nothing? - if (lodash.isEmpty(root.focusedClient)) { - $rootScope.$emit('Local/NoWallets'); - } else { - $rootScope.$emit('Local/NewFocusedWallet'); - - // Set update period - lodash.each(root.walletClients, function(client, id) { - client.setNotificationsInterval(BACKGROUND_UPDATE_PERIOD); - }); - root.focusedClient.setNotificationsInterval(FOREGROUND_UPDATE_PERIOD); - } - - return cb(); - }; - - root.setAndStoreFocus = function(walletId, cb) { - root._setFocus(walletId, function() { - storageService.storeFocusedWalletId(walletId, cb); - }); - }; - - // Adds a wallet client to profileService - root.bindWalletClient = function(client, opts) { - var opts = opts || {}; - var walletId = client.credentials.walletId; - - if ((root.walletClients[walletId] && root.walletClients[walletId].started) || opts.force) { - return false; - } - - root.walletClients[walletId] = client; - root.walletClients[walletId].started = true; - root.walletClients[walletId].doNotVerifyPayPro = isChromeApp; - - client.removeAllListeners(); - client.on('report', function(n) { - $log.info('BWC Report:' + n); - }); - - client.on('notification', function(n) { - $log.debug('BWC Notification:', n); - notificationService.newBWCNotification(n, - walletId, client.credentials.walletName); - - if (root.focusedClient.credentials.walletId == walletId) { - $rootScope.$emit(n.type, n); - } else { - $rootScope.$apply(); - } - }); - - client.on('walletCompleted', function() { - $log.debug('Wallet completed'); - - root.updateCredentials(JSON.parse(client.export()), function() { - $rootScope.$emit('Local/WalletCompleted', walletId); - }); - }); - - if (client.hasPrivKeyEncrypted() && !client.isPrivKeyEncrypted()) { - $log.warn('Auto locking unlocked wallet:' + walletId); - client.lock(); - } - - client.initialize({}, function(err) { - if (err) { - $log.error('Could not init notifications err:', err); - return; - } - client.setNotificationsInterval(BACKGROUND_UPDATE_PERIOD); - }); - - return true; - }; - - var validationLock = false; - - root.runValidation = function(client, delay, retryDelay) { - - delay = delay || 500; - retryDelay = retryDelay || 50; - - if (validationLock) { - return $timeout(function() { - $log.debug('ValidatingWallet Locked: Retrying in: ' + retryDelay); - return root.runValidation(client, delay, retryDelay); - }, retryDelay); - } - validationLock = true; - - // IOS devices are already checked - var skipDeviceValidation = isIOS || root.profile.isDeviceChecked(platformInfo.ua); - var walletId = client.credentials.walletId; - - $log.debug('ValidatingWallet: ' + walletId + ' skip Device:' + skipDeviceValidation); - $timeout(function() { - client.validateKeyDerivation({ - skipDeviceValidation: skipDeviceValidation, - }, function(err, isOK) { - validationLock = false; - - $log.debug('ValidatingWallet End: ' + walletId + ' isOK:' + isOK); - if (isOK) { - root.profile.setChecked(platformInfo.ua, walletId); - } else { - $log.warn('Key Derivation failed for wallet:' + walletId); - storageService.clearLastAddress(walletId, function() {}); - } - - root.storeProfileIfDirty(); - $rootScope.$emit('Local/ValidatingWalletEnded', walletId, isOK); - }); - }, delay); - }; - - // Used when reading wallets from the profile - root.bindWallet = function(credentials, cb) { - if (!credentials.walletId) - return cb('bindWallet should receive credentials JSON'); - - - // Create the client - var getBWSURL = function(walletId) { - var config = configService.getSync(); - var defaults = configService.getDefaults(); - return ((config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url); - }; - - - var client = bwcService.getClient(JSON.stringify(credentials), { - bwsurl: getBWSURL(credentials.walletId), - }); - - var skipKeyValidation = root.profile.isChecked(platformInfo.ua, credentials.walletId); - if (!skipKeyValidation) - root.runValidation(client, 500); - - $log.info('Binding wallet:' + credentials.walletId + ' Validating?:' + !skipKeyValidation); - return cb(null, root.bindWalletClient(client)); - }; - - root.bindProfile = function(profile, cb) { - root.profile = profile; - - configService.get(function(err) { - $log.debug('Preferences read'); - if (err) return cb(err); - - function bindWallets(cb) { - var l = root.profile.credentials.length; - var i = 0, - totalBound = 0; - - if (!l) return cb(); - - lodash.each(root.profile.credentials, function(credentials) { - root.bindWallet(credentials, function(err, bound) { - i++; - totalBound += bound; - if (i == l) { - $log.info('Bound ' + totalBound + ' out of ' + l + ' wallets'); - if (totalBound) - $rootScope.$emit('Local/WalletListUpdated'); - return cb(); - } - }); - }); - } - - bindWallets(function() { - storageService.getFocusedWalletId(function(err, focusedWalletId) { - if (err) return cb(err); - root._setFocus(focusedWalletId, function() { - if (usePushNotifications) - root.pushNotificationsInit(); - - root.isBound = true; - $rootScope.$emit('Local/ProfileBound'); - - root.isDisclaimerAccepted(function(val) { - if (!val) { - return cb(new Error('NONAGREEDDISCLAIMER: Non agreed disclaimer')); - } - $rootScope.$emit('disclaimerAccepted'); - return cb(); - }); - }); - }) - }); - }); - }; - - root.pushNotificationsInit = function() { - var defaults = configService.getDefaults(); - var push = pushNotificationsService.init(root.walletClients); - - push.on('notification', function(data) { - if (!data.additionalData.foreground) { - $log.debug('Push notification event: ', data.message); - - $timeout(function() { - var wallets = root.getWallets(); - var walletToFind = data.additionalData.walletId; - - var walletFound = lodash.find(wallets, function(w) { - return (lodash.isEqual(walletToFind, sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(w.id)))); - }); - - if (!walletFound) return $log.debug('Wallet not found'); - root.setAndStoreFocus(walletFound.id, function() {}); - }, 100); - } - }); - }; - - root.loadAndBindProfile = function(cb) { - storageService.getProfile(function(err, profile) { - if (err) { - $rootScope.$emit('Local/DeviceError', err); - return cb(err); - } - if (!profile) { - // Migration?? - storageService.tryToMigrate(function(err, migratedProfile) { - if (err) return cb(err); - if (!migratedProfile) - return cb(new Error('NOPROFILE: No profile')); - - profile = migratedProfile; - return root.bindProfile(profile, cb); - }) - } else { - $log.debug('Profile read'); - return root.bindProfile(profile, cb); - } - }); - }; - - var seedWallet = function(opts, cb) { - opts = opts || {}; - var walletClient = bwcService.getClient(null, opts); - var network = opts.networkName || 'livenet'; - - if (opts.mnemonic) { - try { - opts.mnemonic = root._normalizeMnemonic(opts.mnemonic); - walletClient.seedFromMnemonic(opts.mnemonic, { - network: network, - passphrase: opts.passphrase, - account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44', - }); - - } catch (ex) { - $log.info(ex); - return cb(gettext('Could not create: Invalid wallet recovery phrase')); - } - } else if (opts.extendedPrivateKey) { - try { - walletClient.seedFromExtendedPrivateKey(opts.extendedPrivateKey); - } catch (ex) { - $log.warn(ex); - return cb(gettext('Could not create using the specified extended private key')); - } - } else if (opts.extendedPublicKey) { - try { - walletClient.seedFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, { - account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44', - }); - } catch (ex) { - $log.warn("Creating wallet from Extended Public Key Arg:", ex, opts); - return cb(gettext('Could not create using the specified extended public key')); - } - } else { - var lang = uxLanguage.getCurrentLanguage(); - try { - walletClient.seedFromRandomWithMnemonic({ - network: network, - passphrase: opts.passphrase, - language: lang, - account: 0, - }); - } catch (e) { - $log.info('Error creating recovery phrase: ' + e.message); - if (e.message.indexOf('language') > 0) { - $log.info('Using default language for recovery phrase'); - walletClient.seedFromRandomWithMnemonic({ - network: network, - passphrase: opts.passphrase, - account: 0, - }); - } else { - return cb(e); - } - } - } - return cb(null, walletClient); - }; - - // Creates a wallet on BWC/BWS - var doCreateWallet = function(opts, cb) { - $log.debug('Creating Wallet:', opts); - $timeout(function() { - seedWallet(opts, function(err, walletClient) { - if (err) return cb(err); - - var name = opts.name || gettextCatalog.getString('Personal Wallet'); - var myName = opts.myName || gettextCatalog.getString('me'); - - walletClient.createWallet(name, myName, opts.m, opts.n, { - network: opts.networkName, - singleAddress: opts.singleAddress, - walletPrivKey: opts.walletPrivKey, - }, function(err, secret) { - if (err) return bwcError.cb(err, gettext('Error creating wallet'), cb); - return cb(null, walletClient, secret); - }); - }); - }, 50); - }; - - // Creates the default Copay profile and its wallet - root.createDefaultProfile = function(opts, cb) { - var p = Profile.create(); - - if (opts.noWallet) { - return cb(null, p); - } - - opts.m = 1; - opts.n = 1; - opts.network = 'livenet'; - - doCreateWallet(opts, function(err, walletClient) { - if (err) return cb(err); - - p.addWallet(JSON.parse(walletClient.export())); - return cb(null, p); - }); - }; - - // create and store a wallet - root.createWallet = function(opts, cb) { - doCreateWallet(opts, function(err, walletClient, secret) { - if (err) return cb(err); - - root.addAndBindWalletClient(walletClient, { - bwsurl: opts.bwsurl - }, cb); - }); - }; - - // joins and stores a wallet - root.joinWallet = function(opts, cb) { - var walletClient = bwcService.getClient(); - $log.debug('Joining Wallet:', opts); - - try { - var walletData = bwcService.parseSecret(opts.secret); - - // check if exist - if (lodash.find(root.profile.credentials, { - 'walletId': walletData.walletId - })) { - return cb(gettext('Cannot join the same wallet more that once')); - } - } catch (ex) { - $log.debug(ex); - return cb(gettext('Bad wallet invitation')); - } - opts.networkName = walletData.network; - $log.debug('Joining Wallet:', opts); - - seedWallet(opts, function(err, walletClient) { - if (err) return cb(err); - - walletClient.joinWallet(opts.secret, opts.myName || 'me', {}, function(err) { - if (err) return bwcError.cb(err, gettext('Could not join wallet'), cb); - root.addAndBindWalletClient(walletClient, { - bwsurl: opts.bwsurl - }, cb); - }); - }); - }; - - root.getClient = function(walletId) { - return root.walletClients[walletId]; - }; - - root.deleteWalletClient = function(client, cb) { - var walletId = client.credentials.walletId; - - pushNotificationsService.unsubscribe(root.getClient(walletId), function(err) { - if (err) $log.warn('Unsubscription error: ' + err.message); - else $log.debug('Unsubscribed from push notifications service'); - }); - - $log.debug('Deleting Wallet:', client.credentials.walletName); - client.removeAllListeners(); - - root.profile.deleteWallet(walletId); - - delete root.walletClients[walletId]; - root.focusedClient = null; - - - storageService.removeAllWalletData(walletId, function(err) { - if (err) $log.warn(err); - }); - - - $timeout(function() { - $rootScope.$emit('Local/WalletListUpdated'); - - root.setAndStoreFocus(null, function() { - storageService.storeProfile(root.profile, function(err) { - if (err) return cb(err); - return cb(); - }); - }); - }); - }; - - root.setMetaData = function(walletClient, addressBook, cb) { - storageService.getAddressbook(walletClient.credentials.network, function(err, localAddressBook) { - var localAddressBook1 = {}; - try { - localAddressBook1 = JSON.parse(localAddressBook); - } catch (ex) { - $log.warn(ex); - } - var mergeAddressBook = lodash.merge(addressBook, localAddressBook1); - storageService.setAddressbook(walletClient.credentials.network, JSON.stringify(addressBook), function(err) { - if (err) return cb(err); - return cb(null); - }); - }); - } - - // Adds and bind a new client to the profile - root.addAndBindWalletClient = function(client, opts, cb) { - if (!client || !client.credentials) - return cb(gettext('Could not access wallet')); - - var walletId = client.credentials.walletId - - if (!root.profile.addWallet(JSON.parse(client.export()))) - return cb(gettext('Wallet already in Copay')); - - - var skipKeyValidation = root.profile.isChecked(platformInfo.ua, walletId); - if (!skipKeyValidation) - root.runValidation(client); - - root.bindWalletClient(client); - $rootScope.$emit('Local/WalletListUpdated', client); - - var saveBwsUrl = function(cb) { - var defaults = configService.getDefaults(); - var bwsFor = {}; - bwsFor[walletId] = opts.bwsurl || defaults.bws.url; - - // Dont save the default - if (bwsFor[walletId] == defaults.bws.url) - return cb(); - - configService.set({ - bwsFor: bwsFor, - }, function(err) { - if (err) $log.warn(err); - return cb(); - }); - }; - - walletService.updateRemotePreferences(client, {}, function() { - $log.debug('Remote preferences saved for:' + walletId) - }); - - saveBwsUrl(function() { - root.setAndStoreFocus(walletId, function() { - storageService.storeProfile(root.profile, function(err) { - var config = configService.getSync(); - if (config.pushNotifications.enabled) - pushNotificationsService.enableNotifications(root.walletClients); - return cb(err, walletId); - }); - - }); - }); - }; - - root.storeProfileIfDirty = function(cb) { - if (root.profile.dirty) { - storageService.storeProfile(root.profile, function(err) { - $log.debug('Saved modified Profile'); - if (cb) return cb(err); - }); - } else { - if (cb) return cb(); - }; - }; - - root.importWallet = function(str, opts, cb) { - - var walletClient = bwcService.getClient(null, opts); - - $log.debug('Importing Wallet:', opts); - try { - walletClient.import(str, { - compressed: opts.compressed, - password: opts.password - }); - } catch (err) { - return cb(gettext('Could not import. Check input file and spending password')); - } - - if (walletClient.hasPrivKeyEncrypted()) { - try { - walletClient.disablePrivateKeyEncryption(); - } catch (e) { - $log.warn(e); - } - } - - str = JSON.parse(str); - - var addressBook = str.addressBook || {}; - - root.addAndBindWalletClient(walletClient, { - bwsurl: opts.bwsurl - }, function(err, walletId) { - if (err) return cb(err); - root.setMetaData(walletClient, addressBook, function(error) { - if (error) $log.warn(error); - return cb(err, walletId); - }); - }); - }; - - root.importExtendedPrivateKey = function(xPrivKey, opts, cb) { - var walletClient = bwcService.getClient(null, opts); - $log.debug('Importing Wallet xPrivKey'); - - walletClient.importFromExtendedPrivateKey(xPrivKey, opts, function(err) { - if (err) { - if (err instanceof errors.NOT_AUTHORIZED) - return cb(err); - - return bwcError.cb(err, gettext('Could not import'), cb); - } - - root.addAndBindWalletClient(walletClient, { - bwsurl: opts.bwsurl - }, cb); - }); - }; - - root._normalizeMnemonic = function(words) { - var isJA = words.indexOf('\u3000') > -1; - var wordList = words.split(/[\u3000\s]+/); - - return wordList.join(isJA ? '\u3000' : ' '); - }; - - root.importMnemonic = function(words, opts, cb) { - var walletClient = bwcService.getClient(null, opts); - - $log.debug('Importing Wallet Mnemonic'); - - words = root._normalizeMnemonic(words); - walletClient.importFromMnemonic(words, { - network: opts.networkName, - passphrase: opts.passphrase, - account: opts.account || 0, - }, function(err) { - if (err) { - if (err instanceof errors.NOT_AUTHORIZED) - return cb(err); - - return bwcError.cb(err, gettext('Could not import'), cb); - } - - root.addAndBindWalletClient(walletClient, { - bwsurl: opts.bwsurl - }, cb); - }); - }; - - root.importExtendedPublicKey = function(opts, cb) { - var walletClient = bwcService.getClient(null, opts); - $log.debug('Importing Wallet XPubKey'); - - walletClient.importFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, { - account: opts.account || 0, - derivationStrategy: opts.derivationStrategy || 'BIP44', - }, function(err) { - if (err) { - - // in HW wallets, req key is always the same. They can't addAccess. - if (err instanceof errors.NOT_AUTHORIZED) - err.name = 'WALLET_DOES_NOT_EXIST'; - - return bwcError.cb(err, gettext('Could not import'), cb); - } - - root.addAndBindWalletClient(walletClient, { - bwsurl: opts.bwsurl - }, cb); - }); - }; - - root.create = function(opts, cb) { - $log.info('Creating profile', opts); - var defaults = configService.getDefaults(); - - configService.get(function(err) { - root.createDefaultProfile(opts, function(err, p) { - if (err) return cb(err); - - storageService.storeNewProfile(p, function(err) { - if (err) return cb(err); - root.bindProfile(p, function(err) { - // ignore NONAGREEDDISCLAIMER - if (err && err.toString().match('NONAGREEDDISCLAIMER')) return cb(); - return cb(err); - }); - }); - }); - }); - }; - - root.setDisclaimerAccepted = function(cb) { - root.profile.disclaimerAccepted = true; - storageService.storeProfile(root.profile, function(err) { - return cb(err); - }); - }; - - root.isDisclaimerAccepted = function(cb) { - var disclaimerAccepted = root.profile && root.profile.disclaimerAccepted; - if (disclaimerAccepted) - return cb(true); - - // OLD flag - storageService.getCopayDisclaimerFlag(function(err, val) { - if (val) { - root.profile.disclaimerAccepted = true; - return cb(true); - } else { - return cb(); - } - }); - }; - - root.updateCredentials = function(credentials, cb) { - root.profile.updateWallet(credentials); - storageService.storeProfile(root.profile, cb); - }; - - root.getClients = function() { - return lodash.values(root.walletClients); - }; - - root.needsBackup = function(client, cb) { - - if (!walletService.needsBackup(client)) - return cb(false); - - storageService.getBackupFlag(client.credentials.walletId, function(err, val) { - if (err) $log.error(err); - if (val) return cb(false); - return cb(true); - }); - }; - - root.isReady = function(client, cb) { - if (!client.isComplete()) - return cb('WALLET_NOT_COMPLETE'); - - root.needsBackup(client, function(needsBackup) { - if (needsBackup) - return cb('WALLET_NEEDS_BACKUP'); - return cb(); - }); - }; - - root.getWallets = function(network, n) { - if (!root.profile) return []; - - var config = configService.getSync(); - config.colorFor = config.colorFor || {}; - config.aliasFor = config.aliasFor || {}; - var ret = lodash.map(root.profile.credentials, function(c) { - return { - m: c.m, - n: c.n, - name: config.aliasFor[c.walletId] || c.walletName, - id: c.walletId, - network: c.network, - color: config.colorFor[c.walletId] || '#4A90E2', - copayerId: c.copayerId - }; - }); - if (network) { - ret = lodash.filter(ret, function(w) { - return (w.network == network); - }); - } - if (n) { - ret = lodash.filter(ret, function(w) { - return (w.n == n); - }); - } - - return lodash.sortBy(ret, 'name'); - }; - - return root; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('pushNotificationsService', function($log, platformInfo, storageService, configService, lodash) { - var root = {}; - var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; - var isIOS = platformInfo.isIOS; - var isAndroid = platformInfo.isAndroid; - - var usePushNotifications = isCordova && !isWP; - - root.init = function(walletsClients) { - var defaults = configService.getDefaults(); - var push = PushNotification.init(defaults.pushNotifications.config); - - push.on('registration', function(data) { - if (root.token) return; - $log.debug('Starting push notification registration'); - root.token = data.registrationId; - var config = configService.getSync(); - if (config.pushNotifications.enabled) root.enableNotifications(walletsClients); - }); - - return push; - } - - root.enableNotifications = function(walletsClients) { - if (!usePushNotifications) return; - - var config = configService.getSync(); - if (!config.pushNotifications.enabled) return; - - if (!root.token) { - $log.warn('No token available for this device. Cannot set push notifications'); - return; - } - - lodash.forEach(walletsClients, function(walletClient) { - var opts = {}; - opts.type = isIOS ? "ios" : isAndroid ? "android" : null; - opts.token = root.token; - root.subscribe(opts, walletClient, function(err, response) { - if (err) $log.warn('Subscription error: ' + err.message + ': ' + JSON.stringify(opts)); - else $log.debug('Subscribed to push notifications service: ' + JSON.stringify(response)); - }); - }); - } - - root.disableNotifications = function(walletsClients) { - if (!usePushNotifications) return; - - lodash.forEach(walletsClients, function(walletClient) { - root.unsubscribe(walletClient, function(err) { - if (err) $log.warn('Unsubscription error: ' + err.message); - else $log.debug('Unsubscribed from push notifications service'); - }); - }); - } - - root.subscribe = function(opts, walletClient, cb) { - if (!usePushNotifications) return cb(); - - var config = configService.getSync(); - if (!config.pushNotifications.enabled) return; - - walletClient.pushNotificationsSubscribe(opts, function(err, resp) { - if (err) return cb(err); - return cb(null, resp); - }); - } - - root.unsubscribe = function(walletClient, cb) { - if (!usePushNotifications) return cb(); - - walletClient.pushNotificationsUnsubscribe(function(err) { - if (err) return cb(err); - return cb(null); - }); - } - - return root; - - }); - -'use strict'; - -//var util = require('util'); -//var _ = require('lodash'); -//var log = require('../util/log'); -//var preconditions = require('preconditions').singleton(); -//var request = require('request'); - -/* - This class lets interfaces with BitPay's exchange rate API. -*/ - -var RateService = function(opts) { - var self = this; - - opts = opts || {}; - self.httprequest = opts.httprequest; // || request; - self.lodash = opts.lodash; - - self.SAT_TO_BTC = 1 / 1e8; - self.BTC_TO_SAT = 1e8; - self.UNAVAILABLE_ERROR = 'Service is not available - check for service.isAvailable() or use service.whenAvailable()'; - self.UNSUPPORTED_CURRENCY_ERROR = 'Currency not supported'; - - self._url = opts.url || 'https://insight.bitpay.com:443/api/rates'; - - self._isAvailable = false; - self._rates = {}; - self._alternatives = []; - self._queued = []; - - self._fetchCurrencies(); -}; - - -var _instance; -RateService.singleton = function(opts) { - if (!_instance) { - _instance = new RateService(opts); - } - return _instance; -}; - -RateService.prototype._fetchCurrencies = function() { - var self = this; - - var backoffSeconds = 5; - var updateFrequencySeconds = 5 * 60; - var rateServiceUrl = 'https://bitpay.com/api/rates'; - - var retrieve = function() { - //log.info('Fetching exchange rates'); - self.httprequest.get(rateServiceUrl).success(function(res) { - self.lodash.each(res, function(currency) { - self._rates[currency.code] = currency.rate; - self._alternatives.push({ - name: currency.name, - isoCode: currency.code, - rate: currency.rate - }); - }); - self._isAvailable = true; - self.lodash.each(self._queued, function(callback) { - setTimeout(callback, 1); - }); - setTimeout(retrieve, updateFrequencySeconds * 1000); - }).error(function(err) { - //log.debug('Error fetching exchange rates', err); - setTimeout(function() { - backoffSeconds *= 1.5; - retrieve(); - }, backoffSeconds * 1000); - return; - }); - - }; - - retrieve(); -}; - -RateService.prototype.getRate = function(code) { - return this._rates[code]; -}; - -RateService.prototype.getHistoricRate = function(code, date, cb) { - var self = this; - - self.httprequest.get(self._url + '/' + code + '?ts=' + date) - .success(function(body) { - return cb(null, body.rate) - }) - .error(function(err) { - return cb(err) - }); - -}; - -RateService.prototype.getHistoricRates = function(code, dates, cb) { - var self = this; - - var tsList = dates.join(','); - - self.httprequest.get(self._url + '/' + code + '?ts=' + tsList) - .success(function(body) { - if (!self.lodash.isArray(body)) { - body = [{ - ts: dates[0], - rate: body.rate - }]; - } - return cb(null, body); - }) - .error(function(err) { - return cb(err) - }); -}; - -RateService.prototype.getAlternatives = function() { - return this._alternatives; -}; - -RateService.prototype.isAvailable = function() { - return this._isAvailable; -}; - -RateService.prototype.whenAvailable = function(callback) { - if (this.isAvailable()) { - setTimeout(callback, 1); - } else { - this._queued.push(callback); - } -}; - -RateService.prototype.toFiat = function(satoshis, code) { - if (!this.isAvailable()) { - return null; - } - - return satoshis * this.SAT_TO_BTC * this.getRate(code); -}; - -RateService.prototype.toFiatHistoric = function(satoshis, code, date, cb) { - var self = this; - - self.getHistoricRate(code, date, function(err, rate) { - if (err) return cb(err); - return cb(null, satoshis * self.SAT_TO_BTC * rate); - }); -}; - -RateService.prototype.fromFiat = function(amount, code) { - if (!this.isAvailable()) { - return null; - } - return amount / this.getRate(code) * this.BTC_TO_SAT; -}; - -RateService.prototype.listAlternatives = function() { - var self = this; - if (!this.isAvailable()) { - return []; - } - - return self.lodash.map(this.getAlternatives(), function(item) { - return { - name: item.name, - isoCode: item.isoCode - } - }); -}; - -angular.module('copayApp.services').factory('rateService', function($http, lodash) { - // var cfg = _.extend(config.rates, { - // httprequest: $http - // }); - - var cfg = { - httprequest: $http, - lodash: lodash - }; - return RateService.singleton(cfg); -}); - - -'use strict'; -angular.module('copayApp.services') - .factory('sjcl', function bitcoreFactory(bwcService) { - var sjcl = bwcService.getSJCL(); - return sjcl; - }); - -'use strict'; -angular.module('copayApp.services') - .factory('storageService', function(logHeader, fileStorageService, localStorageService, sjcl, $log, lodash, platformInfo) { - - var root = {}; - - // File storage is not supported for writing according to - // https://github.com/apache/cordova-plugin-file/#supported-platforms - var shouldUseFileStorage = platformInfo.isCordova && !platformInfo.isWP; - $log.debug('Using file storage:', shouldUseFileStorage); - - - var storage = shouldUseFileStorage ? fileStorageService : localStorageService; - - var getUUID = function(cb) { - // TO SIMULATE MOBILE - //return cb('hola'); - if (!window || !window.plugins || !window.plugins.uniqueDeviceID) - return cb(null); - - window.plugins.uniqueDeviceID.get( - function(uuid) { - return cb(uuid); - }, cb); - }; - - var decryptOnMobile = function(text, cb) { - var json; - try { - json = JSON.parse(text); - } catch (e) { - $log.warn('Could not open profile:' + text); - - var i = text.lastIndexOf('}{'); - if (i > 0) { - text = text.substr(i + 1); - $log.warn('trying last part only:' + text); - try { - json = JSON.parse(text); - $log.warn('Worked... saving.'); - storage.set('profile', text, function() {}); - } catch (e) { - $log.warn('Could not open profile (2nd try):' + e); - }; - }; - - }; - - if (!json) return cb('Could not access storage') - - if (!json.iter || !json.ct) { - $log.debug('Profile is not encrypted'); - return cb(null, text); - } - - $log.debug('Profile is encrypted'); - getUUID(function(uuid) { - $log.debug('Device UUID:' + uuid); - if (!uuid) - return cb('Could not decrypt storage: could not get device ID'); - - try { - text = sjcl.decrypt(uuid, text); - - $log.info('Migrating to unencrypted profile'); - return storage.set('profile', text, function(err) { - return cb(err, text); - }); - } catch (e) { - $log.warn('Decrypt error: ', e); - return cb('Could not decrypt storage: device ID mismatch'); - }; - return cb(null, text); - }); - }; - - - - root.tryToMigrate = function(cb) { - if (!shouldUseFileStorage) return cb(); - - localStorageService.get('profile', function(err, str) { - if (err) return cb(err); - if (!str) return cb(); - - $log.info('Starting Migration profile to File storage...'); - - fileStorageService.create('profile', str, function(err) { - if (err) cb(err); - $log.info('Profile Migrated successfully'); - - localStorageService.get('config', function(err, c) { - if (err) return cb(err); - if (!c) return root.getProfile(cb); - - fileStorageService.create('config', c, function(err) { - - if (err) { - $log.info('Error migrating config: ignoring', err); - return root.getProfile(cb); - } - $log.info('Config Migrated successfully'); - return root.getProfile(cb); - }); - }); - }); - }); - }; - - root.storeNewProfile = function(profile, cb) { - storage.create('profile', profile.toObj(), cb); - }; - - root.storeProfile = function(profile, cb) { - storage.set('profile', profile.toObj(), cb); - }; - - root.getProfile = function(cb) { - storage.get('profile', function(err, str) { - if (err || !str) - return cb(err); - - decryptOnMobile(str, function(err, str) { - if (err) return cb(err); - var p, err; - try { - p = Profile.fromString(str); - } catch (e) { - $log.debug('Could not read profile:', e); - err = new Error('Could not read profile:' + p); - } - return cb(err, p); - }); - }); - }; - - root.deleteProfile = function(cb) { - storage.remove('profile', cb); - }; - - root.storeFocusedWalletId = function(id, cb) { - storage.set('focusedWalletId', id || '', cb); - }; - - root.getFocusedWalletId = function(cb) { - storage.get('focusedWalletId', cb); - }; - - root.getLastAddress = function(walletId, cb) { - storage.get('lastAddress-' + walletId, cb); - }; - - root.storeLastAddress = function(walletId, address, cb) { - storage.set('lastAddress-' + walletId, address, cb); - }; - - root.clearLastAddress = function(walletId, cb) { - storage.remove('lastAddress-' + walletId, cb); - }; - - root.setBackupFlag = function(walletId, cb) { - storage.set('backup-' + walletId, Date.now(), cb); - }; - - root.getBackupFlag = function(walletId, cb) { - storage.get('backup-' + walletId, cb); - }; - - root.clearBackupFlag = function(walletId, cb) { - storage.remove('backup-' + walletId, cb); - }; - - root.setCleanAndScanAddresses = function(walletId, cb) { - storage.set('CleanAndScanAddresses', walletId, cb); - }; - - root.getCleanAndScanAddresses = function(cb) { - storage.get('CleanAndScanAddresses', cb); - }; - - root.removeCleanAndScanAddresses = function(cb) { - storage.remove('CleanAndScanAddresses', cb); - }; - - root.getConfig = function(cb) { - storage.get('config', cb); - }; - - root.storeConfig = function(val, cb) { - $log.debug('Storing Preferences', val); - storage.set('config', val, cb); - }; - - root.clearConfig = function(cb) { - storage.remove('config', cb); - }; - - root.setHideBalanceFlag = function(walletId, val, cb) { - storage.set('hideBalance-' + walletId, val, cb); - }; - - root.getHideBalanceFlag = function(walletId, cb) { - storage.get('hideBalance-' + walletId, cb); - }; - - //for compatibility - root.getCopayDisclaimerFlag = function(cb) { - storage.get('agreeDisclaimer', cb); - }; - - root.setRemotePrefsStoredFlag = function(cb) { - storage.set('remotePrefStored', true, cb); - }; - - root.getRemotePrefsStoredFlag = function(cb) { - storage.get('remotePrefStored', cb); - }; - - root.setGlideraToken = function(network, token, cb) { - storage.set('glideraToken-' + network, token, cb); - }; - - root.getGlideraToken = function(network, cb) { - storage.get('glideraToken-' + network, cb); - }; - - root.removeGlideraToken = function(network, cb) { - storage.remove('glideraToken-' + network, cb); - }; - - root.setCoinbaseRefreshToken = function(network, token, cb) { - storage.set('coinbaseRefreshToken-' + network, token, cb); - }; - - root.getCoinbaseRefreshToken = function(network, cb) { - storage.get('coinbaseRefreshToken-' + network, cb); - }; - - root.removeCoinbaseRefreshToken = function(network, cb) { - storage.remove('coinbaseRefreshToken-' + network, cb); - }; - - root.setCoinbaseToken = function(network, token, cb) { - storage.set('coinbaseToken-' + network, token, cb); - }; - - root.getCoinbaseToken = function(network, cb) { - storage.get('coinbaseToken-' + network, cb); - }; - - root.removeCoinbaseToken = function(network, cb) { - storage.remove('coinbaseToken-' + network, cb); - }; - - root.setAddressbook = function(network, addressbook, cb) { - storage.set('addressbook-' + network, addressbook, cb); - }; - - root.getAddressbook = function(network, cb) { - storage.get('addressbook-' + network, cb); - }; - - root.removeAddressbook = function(network, cb) { - storage.remove('addressbook-' + network, cb); - }; - - - root.checkQuota = function() { - var block = ''; - // 50MB - for (var i = 0; i < 1024*1024; ++ i){ - block += '12345678901234567890123456789012345678901234567890'; - } - storage.set('test', block, function(err) { - $log.error('CheckQuota Return:'+ err); - }); - }; - - root.setTxHistory = function(txs, walletId, cb) { - try { - storage.set('txsHistory-' + walletId, txs, cb); - } catch (e) { - $log.error('Error saving tx History. Size:' + txs.length); - $log.error(e); - return cb(e); - } - } - - root.getTxHistory = function(walletId, cb) { - storage.get('txsHistory-' + walletId, cb); - } - - root.removeTxHistory = function(walletId, cb) { - storage.remove('txsHistory-' + walletId, cb); - } - - root.setCoinbaseTxs = function(network, ctx, cb) { - storage.set('coinbaseTxs-' + network, ctx, cb); - }; - - root.getCoinbaseTxs = function(network, cb) { - storage.get('coinbaseTxs-' + network, cb); - }; - - root.removeCoinbaseTxs = function(network, cb) { - storage.remove('coinbaseTxs-' + network, cb); - }; - - root.removeAllWalletData = function(walletId, cb) { - root.clearLastAddress(walletId, function(err) { - if (err) return cb(err); - root.removeTxHistory(walletId, function(err) { - if (err) return cb(err); - root.clearBackupFlag(walletId, function(err) { - return cb(err); - }); - }); - }); - }; - - return root; - }); - -'use strict'; - -/* - * This is a modification from https://github.com/angular/angular.js/blob/master/src/ngTouch/swipe.js - */ - - -angular.module('copayApp.services') - .factory('$swipe', [ - function() { - // The total distance in any direction before we make the call on swipe vs. scroll. - var MOVE_BUFFER_RADIUS = 10; - - var POINTER_EVENTS = { - 'touch': { - start: 'touchstart', - move: 'touchmove', - end: 'touchend', - cancel: 'touchcancel' - } - }; - - function getCoordinates(event) { - var originalEvent = event.originalEvent || event; - var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent]; - var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0]; - - return { - x: e.clientX, - y: e.clientY - }; - } - - function getEvents(pointerTypes, eventType) { - var res = []; - angular.forEach(pointerTypes, function(pointerType) { - var eventName = POINTER_EVENTS[pointerType][eventType]; - if (eventName) { - res.push(eventName); - } - }); - return res.join(' '); - } - - return { - /** - * @ngdoc method - * @name $swipe#bind - * - * @description - * The main method of `$swipe`. It takes an element to be watched for swipe motions, and an - * object containing event handlers. - * The pointer types that should be used can be specified via the optional - * third argument, which is an array of strings `'mouse'` and `'touch'`. By default, - * `$swipe` will listen for `mouse` and `touch` events. - * - * 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, pointerTypes) { - // 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; - - pointerTypes = pointerTypes || ['touch']; - element.on(getEvents(pointerTypes, 'start'), function(event) { - startCoords = getCoordinates(event); - active = true; - totalX = 0; - totalY = 0; - lastPos = startCoords; - eventHandlers['start'] && eventHandlers['start'](startCoords, event); - }); - var events = getEvents(pointerTypes, 'cancel'); - if (events) { - element.on(events, function(event) { - active = false; - eventHandlers['cancel'] && eventHandlers['cancel'](event); - }); - } - - element.on(getEvents(pointerTypes, 'move'), 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(getEvents(pointerTypes, 'end'), function(event) { - if (!active) return; - active = false; - eventHandlers['end'] && eventHandlers['end'](getCoordinates(event), event); - }); - } - }; - } -]); - - - -'use strict'; - -angular.module('copayApp.services') - .factory('trezor', function($log, $timeout, gettext, lodash, bitcore, hwWallet) { - var root = {}; - - var SETTLE_TIME = 3000; - root.callbacks = {}; - - root.getEntropySource = function(isMultisig, account, callback) { - root.getXPubKey(hwWallet.getEntropyPath('trezor', isMultisig, account), function(data) { - if (!data.success) - return callback(hwWallet._err(data)); - - return callback(null, hwWallet.pubKeyToEntropySource(data.xpubkey)); - }); - }; - - - root.getXPubKey = function(path, callback) { - $log.debug('TREZOR deriving xPub path:', path); - TrezorConnect.getXPubKey(path, callback); - }; - - - root.getInfoForNewWallet = function(isMultisig, account, callback) { - var opts = {}; - root.getEntropySource(isMultisig, account, function(err, data) { - if (err) return callback(err); - opts.entropySource = data; - $log.debug('Waiting TREZOR to settle...'); - $timeout(function() { - - root.getXPubKey(hwWallet.getAddressPath('trezor', isMultisig, account), function(data) { - if (!data.success) - return callback(hwWallet._err(data)); - - opts.extendedPublicKey = data.xpubkey; - opts.externalSource = 'trezor'; - opts.account = account; - - if (isMultisig) - opts.derivationStrategy = 'BIP48'; - - return callback(null, opts); - }); - }, SETTLE_TIME); - }); - }; - - root._orderPubKeys = function(xPub, np) { - var xPubKeys = lodash.clone(xPub); - var path = lodash.clone(np); - path.unshift('m'); - path = path.join('/'); - - var keys = lodash.map(xPubKeys, function(x) { - var pub = (new bitcore.HDPublicKey(x)).derive(path).publicKey; - return { - xpub: x, - pub: pub.toString('hex'), - }; - }); - - var sorted = lodash.sortBy(keys, function(x) { - return x.pub; - }); - - return lodash.pluck(sorted, 'xpub'); - }; - - root.signTx = function(xPubKeys, txp, account, callback) { - - var inputs = [], - outputs = []; - var tmpOutputs = []; - - - if (txp.type && txp.type != 'simple') { - return callback('Only TXPs type SIMPLE are supported in TREZOR'); - } else if (txp.outputs) { - if (txp.outputs.length > 1) - return callback('Only single output TXPs are supported in TREZOR'); - } else { - return callback('Unknown TXP at TREZOR'); - } - - if (txp.outputs) { - - if (!txp.toAddress) - txp.toAddress = txp.outputs[0].toAddress; - - if (!txp.amount) - txp.amount = txp.outputs[0].amount; - } - - if (!txp.toAddress || !txp.amount) - return callback('No address or amount at TREZOR signing'); - - - var toScriptType = 'PAYTOADDRESS'; - if (txp.toAddress.charAt(0) == '2' || txp.toAddress.charAt(0) == '3') - toScriptType = 'PAYTOSCRIPTHASH'; - - - // Add to - tmpOutputs.push({ - address: txp.toAddress, - amount: txp.amount, - script_type: toScriptType, - }); - - - - if (txp.addressType == 'P2PKH') { - - $log.debug("Trezor signing uni-sig p2pkh. Account:", account); - - var inAmount = 0; - inputs = lodash.map(txp.inputs, function(i) { - $log.debug("Trezor TX input path:", i.path); - var pathArr = i.path.split('/'); - var n = [hwWallet.UNISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])]; - inAmount += i.satoshis; - return { - address_n: n, - prev_index: i.vout, - prev_hash: i.txid, - }; - }); - - var change = inAmount - txp.fee - txp.amount; - if (change > 0) { - $log.debug("Trezor TX change path:", txp.changeAddress.path); - var pathArr = txp.changeAddress.path.split('/'); - var n = [hwWallet.UNISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])]; - - tmpOutputs.push({ - address_n: n, - amount: change, - script_type: 'PAYTOADDRESS' - }); - } - - } else { - - // P2SH Wallet, multisig wallet - var inAmount = 0; - $log.debug("Trezor signing multi-sig p2sh. Account:", account); - - var sigs = xPubKeys.map(function(v) { - return ''; - }); - - - inputs = lodash.map(txp.inputs, function(i) { - $log.debug("Trezor TX input path:", i.path); - var pathArr = i.path.split('/'); - var n = [hwWallet.MULTISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])]; - var np = n.slice(3); - - inAmount += i.satoshis; - - var orderedPubKeys = root._orderPubKeys(xPubKeys, np); - var pubkeys = lodash(orderedPubKeys.map(function(v) { - return { - node: v, - address_n: np, - }; - })); - - return { - address_n: n, - prev_index: i.vout, - prev_hash: i.txid, - script_type: 'SPENDMULTISIG', - multisig: { - pubkeys: pubkeys, - signatures: sigs, - m: txp.requiredSignatures, - } - }; - }); - - var change = inAmount - txp.fee - txp.amount; - if (change > 0) { - $log.debug("Trezor TX change path:", txp.changeAddress.path); - var pathArr = txp.changeAddress.path.split('/'); - var n = [hwWallet.MULTISIG_ROOTPATH | 0x80000000, 0 | 0x80000000, account | 0x80000000, parseInt(pathArr[1]), parseInt(pathArr[2])]; - var np = n.slice(3); - - var orderedPubKeys = root._orderPubKeys(xPubKeys, np); - var pubkeys = lodash(orderedPubKeys.map(function(v) { - return { - node: v, - address_n: np, - }; - })); - - tmpOutputs.push({ - address_n: n, - amount: change, - script_type: 'PAYTOMULTISIG', - multisig: { - pubkeys: pubkeys, - signatures: sigs, - m: txp.requiredSignatures, - } - }); - } - } - - // Shuffle outputs for improved privacy - if (tmpOutputs.length > 1) { - outputs = new Array(tmpOutputs.length); - lodash.each(txp.outputOrder, function(order) { - outputs[order] = tmpOutputs.shift(); - }); - - if (tmpOutputs.length) - return cb("Error creating transaction: tmpOutput order"); - } else { - outputs = tmpOutputs; - } - - // Prevents: Uncaught DataCloneError: Failed to execute 'postMessage' on 'Window': An object could not be cloned. - inputs = JSON.parse(JSON.stringify(inputs)); - outputs = JSON.parse(JSON.stringify(outputs)); - - $log.debug('Signing with TREZOR', inputs, outputs); - TrezorConnect.signTx(inputs, outputs, function(res) { - if (!res.success) - return callback(hwWallet._err(res)); - - callback(null, res); - }); - }; - - return root; - }); - -'use strict'; - -angular.module('copayApp.services').factory('txFormatService', function(profileService, rateService, configService, lodash) { - var root = {}; - - var formatAmountStr = function(amount) { - if (!amount) return; - var config = configService.getSync().wallet.settings; - return profileService.formatAmount(amount) + ' ' + config.unitName; - }; - - var formatAlternativeStr = function(amount) { - if (!amount) return; - var config = configService.getSync().wallet.settings; - return (rateService.toFiat(amount, config.alternativeIsoCode) ? rateService.toFiat(amount, config.alternativeIsoCode).toFixed(2) : 'N/A') + ' ' + config.alternativeIsoCode; - }; - - var formatFeeStr = function(fee) { - if (!fee) return; - var config = configService.getSync().wallet.settings; - return profileService.formatAmount(fee) + ' ' + config.unitName; - }; - - root.processTx = function(tx) { - if (!tx || tx.action == 'invalid') - return tx; - - // New transaction output format - if (tx.outputs && tx.outputs.length) { - - var outputsNr = tx.outputs.length; - - if (tx.action != 'received') { - if (outputsNr > 1) { - tx.recipientCount = outputsNr; - tx.hasMultiplesOutputs = true; - } - tx.amount = lodash.reduce(tx.outputs, function(total, o) { - o.amountStr = formatAmountStr(o.amount); - o.alternativeAmountStr = formatAlternativeStr(o.amount); - return total + o.amount; - }, 0); - } - tx.toAddress = tx.outputs[0].toAddress; - } - - tx.amountStr = formatAmountStr(tx.amount); - tx.alternativeAmountStr = formatAlternativeStr(tx.amount); - tx.feeStr = formatFeeStr(tx.fee || tx.fees); - - return tx; - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.services').factory('txStatus', function(lodash, profileService, $timeout, platformInfo) { - var root = {}; - var isCordova = platformInfo.isCordova; - - root.notify = function(txp) { - var fc = profileService.focusedClient; - var status = txp.status; - var type; - var INMEDIATE_SECS = 10; - - if (status == 'broadcasted') { - type = 'broadcasted'; - } else { - - var n = txp.actions.length; - var action = lodash.find(txp.actions, { - copayerId: fc.credentials.copayerId - }); - - if (!action) { - type = 'created'; - } else if (action.type == 'accept') { - // created and accepted at the same time? - if (n == 1 && action.createdOn - txp.createdOn < INMEDIATE_SECS) { - type = 'created'; - } else { - type = 'accepted'; - } - } else if (action.type == 'reject') { - type = 'rejected'; - } else { - throw new Error('Unknown type:' + type); - } - } - return type; - }; - - return root; -}); - -'use strict'; -angular.module('copayApp.services') - .factory('uxLanguage', function languageService($log, lodash, gettextCatalog, amMoment, configService) { - var root = {}; - - root.currentLanguage = null; - - root.availableLanguages = [{ - name: 'English', - isoCode: 'en', - }, { - name: 'Český', - isoCode: 'cs', - }, { - name: 'Français', - isoCode: 'fr', - }, { - name: 'Italiano', - isoCode: 'it', - }, { - name: 'Deutsch', - isoCode: 'de', - }, { - name: 'Español', - isoCode: 'es', - }, { - name: '日本語', - isoCode: 'ja', - useIdeograms: true, - }, { - name: '中文(简体)', - isoCode: 'zh', - useIdeograms: true, - }, { - name: 'Polski', - isoCode: 'pl', - }, { - name: 'Pусский', - isoCode: 'ru', - }]; - - - root._detect = function(cb) { - - var userLang, androidLang; - if (navigator && navigator.globalization) { - - navigator.globalization.getPreferredLanguage(function(preferedLanguage) { - // works for iOS and Android 4.x - userLang = preferedLanguage.value; - userLang = userLang ? (userLang.split('-', 1)[0] || 'en') : 'en'; - // Set only available languages - userLang = root.isAvailableLanguage(userLang); - return cb(userLang); - }); - } else { - // Auto-detect browser language - userLang = navigator.userLanguage || navigator.language; - userLang = userLang ? (userLang.split('-', 1)[0] || 'en') : 'en'; - // Set only available languages - userLang = root.isAvailableLanguage(userLang); - return cb(userLang); - } - }; - - root.isAvailableLanguage = function(userLang) { - return lodash.find(root.availableLanguages, { - 'isoCode': userLang - }) ? userLang : 'en'; - }; - - root._set = function(lang) { - $log.debug('Setting default language: ' + lang); - gettextCatalog.setCurrentLanguage(lang); - root.currentLanguage = lang; - if (lang == 'zh') lang = lang + '-CN'; // Fix for Chinese Simplified - amMoment.changeLocale(lang); - }; - - root.getCurrentLanguage = function() { - return root.currentLanguage; - }; - - root.getCurrentLanguageName = function() { - return root.getName(root.currentLanguage); - }; - - root.getCurrentLanguageInfo = function() { - return lodash.find(root.availableLanguages, { - 'isoCode': root.currentLanguage - }); - }; - - root.getLanguages = function() { - return root.availableLanguages; - }; - - root.init = function() { - root._detect(function(lang) { - root._set(lang); - }); - }; - - root.update = function(cb) { - var userLang = configService.getSync().wallet.settings.defaultLanguage; - - if (!userLang) { - root._detect(function(lang) { - userLang = lang; - - if (userLang != root.currentLanguage) { - root._set(lang); - } - if (cb) return cb(userLang); - }); - } else { - if (userLang != root.currentLanguage) { - root._set(userLang); - } - - if (cb) return cb(userLang); - } - }; - - root.getName = function(lang) { - return lodash.result(lodash.find(root.availableLanguages, { - 'isoCode': lang - }), 'name'); - }; - - return root; - }); - -'use strict'; - -// DO NOT INCLUDE STORAGE HERE \/ \/ -angular.module('copayApp.services').factory('walletService', function($log, lodash, trezor, ledger, storageService, configService, uxLanguage) { -// DO NOT INCLUDE STORAGE HERE ^^ - - var root = {}; - - var _signWithLedger = function(client, txp, cb) { - $log.info('Requesting Ledger Chrome app to sign the transaction'); - - ledger.signTx(txp, client.credentials.account, function(result) { - $log.debug('Ledger response', result); - if (!result.success) - return cb(result.message || result.error); - - txp.signatures = lodash.map(result.signatures, function(s) { - return s.substring(0, s.length - 2); - }); - return client.signTxProposal(txp, cb); - }); - }; - - var _signWithTrezor = function(client, txp, cb) { - $log.info('Requesting Trezor to sign the transaction'); - - var xPubKeys = lodash.pluck(client.credentials.publicKeyRing, 'xPubKey'); - trezor.signTx(xPubKeys, txp, client.credentials.account, function(err, result) { - if (err) return cb(err); - - $log.debug('Trezor response', result); - txp.signatures = result.signatures; - return client.signTxProposal(txp, cb); - }); - }; - - root.needsBackup = function(client) { - if (client.isPrivKeyExternal()) return false; - if (!client.credentials.mnemonic) return false; - if (client.credentials.network == 'testnet') return false; - - return true; - }; - - - root.isEncrypted = function(client) { - if (lodash.isEmpty(client)) return; - var isEncrypted = client.isPrivKeyEncrypted(); - if (isEncrypted) $log.debug('Wallet is encrypted'); - return isEncrypted; - }; - - root.lock = function(client) { - try { - client.lock(); - } catch (e) { - $log.warn('Encrypting wallet:', e); - }; - }; - - root.unlock = function(client, password) { - if (lodash.isEmpty(client)) - return 'MISSING_PARAMETER'; - if (lodash.isEmpty(password)) - return 'NO_PASSWORD_GIVEN'; - try { - client.unlock(password); - } catch (e) { - $log.warn('Decrypting wallet:', e); - return 'PASSWORD_INCORRECT'; - } - }; - - root.createTx = function(client, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(client)) - return cb('MISSING_PARAMETER'); - - if (txp.sendMax) { - client.createTxProposal(txp, function(err, createdTxp) { - if (err) return cb(err); - else return cb(null, createdTxp); - }); - } else { - client.getFeeLevels(client.credentials.network, function(err, levels) { - if (err) return cb(err); - - var feeLevelValue = lodash.find(levels, { - level: txp.feeLevel - }); - - if (!feeLevelValue || !feeLevelValue.feePerKB) - return cb({ - message: 'Could not get dynamic fee for level: ' + feeLevel - }); - - $log.debug('Dynamic fee: ' + txp.feeLevel + ' ' + feeLevelValue.feePerKB + ' SAT'); - - txp.feePerKb = feeLevelValue.feePerKB; - client.createTxProposal(txp, function(err, createdTxp) { - if (err) return cb(err); - else { - $log.debug('Transaction created'); - return cb(null, createdTxp); - } - }); - }); - } - }; - - root.publishTx = function(client, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(client)) - return cb('MISSING_PARAMETER'); - - client.publishTxProposal({ - txp: txp - }, function(err, publishedTx) { - if (err) return cb(err); - else { - $log.debug('Transaction published'); - return cb(null, publishedTx); - } - }); - }; - - root.signTx = function(client, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(client)) - return cb('MISSING_PARAMETER'); - - if (client.isPrivKeyExternal()) { - switch (client.getPrivKeyExternalSourceName()) { - case 'ledger': - return _signWithLedger(client, txp, cb); - case 'trezor': - return _signWithTrezor(client, txp, cb); - default: - var msg = 'Unsupported External Key:' + client.getPrivKeyExternalSourceName(); - $log.error(msg); - return cb(msg); - } - } else { - - try { - client.signTxProposal(txp, function(err, signedTxp) { - $log.debug('Transaction signed'); - return cb(err, signedTxp); - }); - } catch (e) { - $log.warn('Error at signTxProposal:', e); - return cb(e); - } - } - }; - - root.broadcastTx = function(client, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(client)) - return cb('MISSING_PARAMETER'); - - if (txp.status != 'accepted') - return cb('TX_NOT_ACCEPTED'); - - client.broadcastTxProposal(txp, function(err, broadcastedTxp, memo) { - if (err) - return cb(err); - - $log.debug('Transaction broadcasted'); - if (memo) $log.info(memo); - - return cb(null, broadcastedTxp); - }); - }; - - root.rejectTx = function(client, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(client)) - return cb('MISSING_PARAMETER'); - - client.rejectTxProposal(txp, null, function(err, rejectedTxp) { - $log.debug('Transaction rejected'); - return cb(err, rejectedTxp); - }); - }; - - root.removeTx = function(client, txp, cb) { - if (lodash.isEmpty(txp) || lodash.isEmpty(client)) - return cb('MISSING_PARAMETER'); - - client.removeTxProposal(txp, function(err) { - $log.debug('Transaction removed'); - return cb(err); - }); - }; - - root.updateRemotePreferences = function(clients, prefs, cb) { - prefs = prefs || {}; - - if (!lodash.isArray(clients)) - clients = [clients]; - - function updateRemotePreferencesFor(clients, prefs, cb) { - var client = clients.shift(); - if (!client) return cb(); - $log.debug('Saving remote preferences', client.credentials.walletName, prefs); - - client.savePreferences(prefs, function(err) { - // we ignore errors here - if (err) $log.warn(err); - - updateRemotePreferencesFor(clients, prefs, cb); - }); - }; - - // Update this JIC. - var config = configService.getSync().wallet.settings; - - //prefs.email (may come from arguments) - prefs.language = uxLanguage.getCurrentLanguage(); - prefs.unit = config.unitCode; - - updateRemotePreferencesFor(clients, prefs, function(err) { - if (err) return cb(err); - - lodash.each(clients, function(c) { - c.preferences = lodash.assign(prefs, c.preferences); - }); - return cb(); - }); - }; - - return root; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('backupController', - function($rootScope, $scope, $timeout, $log, go, lodash, fingerprintService, platformInfo, configService, profileService, gettext, bwcService, walletService, ongoingProcess) { - - var fc = profileService.focusedClient; - var prevState; - $scope.customWords = []; - $scope.walletName = fc.credentials.walletName; - $scope.credentialsEncrypted = fc.isPrivKeyEncrypted; - - $scope.init = function(state) { - prevState = state || 'walletHome'; - $scope.step = 1; - $scope.deleted = isDeletedSeed(); - if ($scope.deleted) return; - - fingerprintService.check(fc, function(err) { - if (err) { - go.path(prevState); - return; - } - - handleEncryptedWallet(fc, function(err) { - if (err) { - $log.warn('Error decrypting credentials:', $scope.error); - go.path(prevState); - return; - } - $scope.credentialsEncrypted = false; - $scope.initFlow(); - }); - }); - }; - - function shuffledWords(words) { - var sort = lodash.sortBy(words); - - return lodash.map(sort, function(w) { - return { - word: w, - selected: false - }; - }); - }; - - $scope.initFlow = function() { - var words = fc.getMnemonic(); - $scope.xPrivKey = fc.credentials.xPrivKey; - $scope.mnemonicWords = words.split(/[\u3000\s]+/); - $scope.shuffledMnemonicWords = shuffledWords($scope.mnemonicWords); - $scope.mnemonicHasPassphrase = fc.mnemonicHasPassphrase(); - $scope.useIdeograms = words.indexOf("\u3000") >= 0; - $scope.passphrase = ''; - $scope.customWords = []; - $scope.step = 1; - $scope.selectComplete = false; - $scope.backupError = false; - - $timeout(function() { - $scope.$apply(); - }, 10); - }; - - function isDeletedSeed() { - if (lodash.isEmpty(fc.credentials.mnemonic) && lodash.isEmpty(fc.credentials.mnemonicEncrypted)) - return true; - return false; - }; - - $scope.goBack = function() { - go.path(prevState || 'walletHome'); - }; - - $scope.$on('$destroy', function() { - walletService.lock(fc); - }); - - $scope.goToStep = function(n) { - if (n == 1) - $scope.initFlow(); - if (n == 2) - $scope.step = 2; - if (n == 3) { - if (!$scope.mnemonicHasPassphrase) - finalStep(); - else - $scope.step = 3; - } - if (n == 4) - finalStep(); - - function finalStep() { - ongoingProcess.set('validatingWords', true); - confirm(function(err) { - ongoingProcess.set('validatingWords', false); - if (err) { - backupError(err); - } - $timeout(function() { - $scope.step = 4; - return; - }, 1); - }); - }; - }; - - $scope.addButton = function(index, item) { - var newWord = { - word: item.word, - prevIndex: index - }; - $scope.customWords.push(newWord); - $scope.shuffledMnemonicWords[index].selected = true; - $scope.shouldContinue(); - }; - - $scope.removeButton = function(index, item) { - if ($scope.loading) return; - $scope.customWords.splice(index, 1); - $scope.shuffledMnemonicWords[item.prevIndex].selected = false; - $scope.shouldContinue(); - }; - - $scope.shouldContinue = function() { - if ($scope.customWords.length == $scope.shuffledMnemonicWords.length) - $scope.selectComplete = true; - else - $scope.selectComplete = false; - }; - - function confirm(cb) { - $scope.backupError = false; - - var customWordList = lodash.pluck($scope.customWords, 'word'); - - if (!lodash.isEqual($scope.mnemonicWords, customWordList)) { - return cb('Mnemonic string mismatch'); - } - - $timeout(function() { - if ($scope.mnemonicHasPassphrase) { - var walletClient = bwcService.getClient(); - var separator = $scope.useIdeograms ? '\u3000' : ' '; - var customSentence = customWordList.join(separator); - var passphrase = $scope.passphrase || ''; - - try { - walletClient.seedFromMnemonic(customSentence, { - network: fc.credentials.network, - passphrase: passphrase, - account: fc.credentials.account - }); - } catch (err) { - return cb(err); - } - - if (walletClient.credentials.xPrivKey != $scope.xPrivKey) { - return cb('Private key mismatch'); - } - } - - $rootScope.$emit('Local/BackupDone'); - return cb(); - }, 1); - }; - - function handleEncryptedWallet(client, cb) { - if (!walletService.isEncrypted(client)) { - $scope.credentialsEncrypted = false; - return cb(); - } - - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - - function backupError(err) { - ongoingProcess.set('validatingWords', false); - $log.debug('Failed to verify backup: ', err); - $scope.backupError = true; - - $timeout(function() { - $scope.$apply(); - }, 1); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('buyCoinbaseController', - function($scope, $log, $ionicModal, $timeout, lodash, profileService, coinbaseService, addressService, ongoingProcess) { - var self = this; - - this.init = function(testnet) { - self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet'); - - var client = profileService.focusedClient; - if (client) { - $timeout(function() { - self.selectedWalletId = client.credentials.walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - } - }; - - this.getPaymentMethods = function(token) { - coinbaseService.getPaymentMethods(token, function(err, p) { - if (err) { - self.error = err; - return; - } - self.paymentMethods = []; - lodash.each(p.data, function(pm) { - if (pm.allow_buy) { - self.paymentMethods.push(pm); - } - if (pm.allow_buy && pm.primary_buy) { - $scope.selectedPaymentMethod = pm; - } - }); - }); - }; - - this.getPrice = function(token) { - var currency = 'USD'; - coinbaseService.buyPrice(token, currency, function(err, b) { - if (err) return; - self.buyPrice = b.data || null; - }); - }; - - $scope.openWalletsModal = function(wallets) { - self.error = null; - - $scope.type = 'BUY'; - $scope.wallets = wallets; - $scope.noColor = true; - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/wallets.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.walletsModal = modal; - $scope.walletsModal.show(); - }); - - $scope.$on('walletSelected', function(ev, walletId) { - $timeout(function() { - var client = profileService.getClient(walletId); - self.selectedWalletId = walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - $scope.walletsModal.hide(); - }); - }; - - this.buyRequest = function(token, account) { - self.error = null; - var accountId = account.id; - var amount = $scope.amount ? $scope.amount : $scope.fiat; - var currency = $scope.amount ? 'BTC' : 'USD'; - if (!amount) return; - var dataSrc = { - amount: amount, - currency: currency, - payment_method: $scope.selectedPaymentMethod.id || null - }; - ongoingProcess.set('Sending request...', true); - coinbaseService.buyRequest(token, accountId, dataSrc, function(err, data) { - ongoingProcess.set('Sending request...', false); - if (err) { - self.error = err; - return; - } - self.buyInfo = data.data; - }); - }; - - this.confirmBuy = function(token, account, buy) { - self.error = null; - var accountId = account.id; - var buyId = buy.id; - ongoingProcess.set('Buying Bitcoin...', true); - coinbaseService.buyCommit(token, accountId, buyId, function(err, b) { - ongoingProcess.set('Buying Bitcoin...', false); - if (err) { - self.error = err; - return; - } else { - var tx = b.data.transaction; - if (!tx) return; - - ongoingProcess.set('Fetching transaction...', true); - coinbaseService.getTransaction(token, accountId, tx.id, function(err, updatedTx) { - ongoingProcess.set('Fetching transaction...', false); - if (err) $log.debug(err); - addressService.getAddress(self.selectedWalletId, false, function(err, addr) { - if (err) { - self.error = { - errors: [{ - message: 'Could not create address' - }] - }; - return; - } - updatedTx.data['toAddr'] = addr; - coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) { - if (err) $log.debug(err); - if (updatedTx.data.status == 'completed') { - self.sendToCopay(token, account, updatedTx.data); - } else { - self.success = updatedTx.data; - $timeout(function() { - $scope.$emit('Local/CoinbaseTx'); - }, 1000); - } - }); - }); - }); - } - }); - }; - - this.sendToCopay = function(token, account, tx) { - self.error = null; - var accountId = account.id; - - ongoingProcess.set('Sending funds to Copay...', true); - var data = { - to: tx.toAddr, - amount: tx.amount.amount, - currency: tx.amount.currency, - description: 'Copay Wallet: ' + self.selectedWalletName - }; - coinbaseService.sendTo(token, accountId, data, function(err, res) { - ongoingProcess.set('Sending funds to Copay...', false); - if (err) { - self.error = err; - } else { - self.receiveInfo = res.data; - if (!res.data.id) return; - coinbaseService.getTransaction(token, accountId, res.data.id, function(err, sendTx) { - coinbaseService.savePendingTransaction(tx, { - remove: true - }, function(err) { - coinbaseService.savePendingTransaction(sendTx.data, {}, function(err) { - $timeout(function() { - $scope.$emit('Local/CoinbaseTx'); - }, 1000); - }); - }); - }); - } - - }); - }; - - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('buyGlideraController', - function($scope, $timeout, $ionicModal, profileService, addressService, glideraService, bwcError, lodash, ongoingProcess) { - - var self = this; - this.show2faCodeInput = null; - this.error = null; - this.success = null; - - this.init = function(testnet) { - self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet'); - - var client = profileService.focusedClient; - if (client) { - $timeout(function() { - self.selectedWalletId = client.credentials.walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - } - }; - - $scope.openWalletsModal = function(wallets) { - self.error = null; - - $scope.type = 'BUY'; - $scope.wallets = wallets; - $scope.noColor = true; - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/wallets.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.walletsModal = modal; - $scope.walletsModal.show(); - }); - - $scope.$on('walletSelected', function(ev, walletId) { - $timeout(function() { - var client = profileService.getClient(walletId); - self.selectedWalletId = walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - $scope.walletsModal.hide(); - }); - }; - - this.getBuyPrice = function(token, price) { - var self = this; - this.error = null; - if (!price || (price && !price.qty && !price.fiat)) { - this.buyPrice = null; - return; - } - this.gettingBuyPrice = true; - glideraService.buyPrice(token, price, function(err, buyPrice) { - self.gettingBuyPrice = false; - if (err) { - self.error = 'Could not get exchange information. Please, try again.'; - return; - } - self.buyPrice = buyPrice; - }); - }; - - this.get2faCode = function(token) { - var self = this; - self.error = null; - ongoingProcess.set('Sending 2FA code...', true); - $timeout(function() { - glideraService.get2faCode(token, function(err, sent) { - ongoingProcess.set('Sending 2FA code...', false); - if (err) { - self.error = 'Could not send confirmation code to your phone'; - return; - } - self.show2faCodeInput = sent; - }); - }, 100); - }; - - this.sendRequest = function(token, permissions, twoFaCode) { - var self = this; - self.error = null; - ongoingProcess.set('Buying Bitcoin...', true); - $timeout(function() { - addressService.getAddress(self.selectedWalletId, false, function(err, walletAddr) { - if (err) { - ongoingProcess.set('Buying Bitcoin...', false); - self.error = bwcError.cb(err, 'Could not create address'); - return; - } - var data = { - destinationAddress: walletAddr, - qty: self.buyPrice.qty, - priceUuid: self.buyPrice.priceUuid, - useCurrentPrice: false, - ip: null - }; - glideraService.buy(token, twoFaCode, data, function(err, data) { - ongoingProcess.set('Buying Bitcoin...', false); - if (err) { - self.error = err; - return; - } - self.success = data; - $scope.$emit('Local/GlideraTx'); - }); - }); - }, 100); - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('coinbaseController', - function($rootScope, $scope, $timeout, $ionicModal, profileService, configService, storageService, coinbaseService, lodash, platformInfo, ongoingProcess) { - - var isNW = platformInfo.isNW; - - this.openAuthenticateWindow = function() { - var oauthUrl = this.getAuthenticateUrl(); - if (!isNW) { - $rootScope.openExternalLink(oauthUrl, '_system'); - } else { - var self = this; - var gui = require('nw.gui'); - var win = gui.Window.open(oauthUrl, { - focus: true, - position: 'center' - }); - win.on('loaded', function() { - var title = win.title; - if (title.indexOf('Coinbase') == -1) { - $scope.code = title; - self.submitOauthCode(title); - win.close(); - } - }); - } - } - - this.getAuthenticateUrl = function() { - return coinbaseService.getOauthCodeUrl(); - }; - - this.submitOauthCode = function(code) { - var self = this; - var coinbaseTestnet = configService.getSync().coinbase.testnet; - var network = coinbaseTestnet ? 'testnet' : 'livenet'; - ongoingProcess.set('connectingCoinbase', true); - this.error = null; - $timeout(function() { - coinbaseService.getToken(code, function(err, data) { - ongoingProcess.set('connectingCoinbase', false); - if (err) { - self.error = err; - $timeout(function() { - $scope.$apply(); - }, 100); - } else if (data && data.access_token && data.refresh_token) { - storageService.setCoinbaseToken(network, data.access_token, function() { - storageService.setCoinbaseRefreshToken(network, data.refresh_token, function() { - $scope.$emit('Local/CoinbaseUpdated', data.access_token); - $timeout(function() { - $scope.$apply(); - }, 100); - }); - }); - } - }); - }, 100); - }; - - this.openTxModal = function(tx) { - $scope.tx = tx; - - $ionicModal.fromTemplateUrl('views/modals/coinbase-tx-details.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.coinbaseTxDetailsModal = modal; - $scope.coinbaseTxDetailsModal.show(); - }); - }; - - }); - -'use strict'; -angular.module('copayApp.controllers').controller('coinbaseUriController', - function($scope, $stateParams, $timeout, profileService, configService, coinbaseService, storageService, go, ongoingProcess) { - - this.submitOauthCode = function(code) { - var self = this; - var coinbaseTestnet = configService.getSync().coinbase.testnet; - var network = coinbaseTestnet ? 'testnet' : 'livenet'; - ongoingProcess.set('connectingCoinbase', true); - this.error = null; - $timeout(function() { - coinbaseService.getToken(code, function(err, data) { - ongoingProcess.set('connectingCoinbase', false); - if (err) { - self.error = err; - $timeout(function() { - $scope.$apply(); - }, 100); - } else if (data && data.access_token && data.refresh_token) { - storageService.setCoinbaseToken(network, data.access_token, function() { - storageService.setCoinbaseRefreshToken(network, data.refresh_token, function() { - $scope.$emit('Local/CoinbaseUpdated', data.access_token); - $timeout(function() { - go.path('coinbase'); - $scope.$apply(); - }, 100); - }); - }); - } - }); - }, 100); - }; - - this.checkCode = function() { - if ($stateParams.url) { - var match = $stateParams.url.match(/code=(.+)&/); - if (match && match[1]) { - this.code = match[1]; - return this.submitOauthCode(this.code); - } - } - $log.error('Bad state: ' + JSON.stringify($stateParams)); - } - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('copayersController', - function($scope, $rootScope, $timeout, $log, $ionicModal, profileService, go, notification, platformInfo, gettext, gettextCatalog) { - var self = this; - var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; - var isAndroid = platformInfo.isAndroid; - - var delete_msg = gettextCatalog.getString('Are you sure you want to delete this wallet?'); - var accept_msg = gettextCatalog.getString('Accept'); - var cancel_msg = gettextCatalog.getString('Cancel'); - var confirm_msg = gettextCatalog.getString('Confirm'); - - // Note that this is ONLY triggered when the page is opened - // IF a wallet is incomplete and copay is at /#copayers - // and the user switch to an other complete wallet - // THIS IS NOT TRIGGERED. - // - self.init = function() { - var fc = profileService.focusedClient; - if (fc.isComplete()) { - $log.debug('Wallet Complete...redirecting') - go.walletHome(); - return; - } - }; - - var _modalDeleteWallet = function() { - $scope.title = delete_msg; - $scope.accept_msg = accept_msg; - $scope.cancel_msg = cancel_msg; - $scope.confirm_msg = confirm_msg; - $scope.okAction = doDeleteWallet; - $scope.loading = false; - - $ionicModal.fromTemplateUrl('views/modals/confirmation.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.confirmationModal = modal; - $scope.confirmationModal.show(); - }); - }; - - var doDeleteWallet = function() { - var fc = profileService.focusedClient; - var walletName = fc.credentials.walletName; - profileService.deleteWalletClient(fc, function(err) { - if (err) { - self.error = err.message || err; - $timeout(function() { - $scope.$digest(); - }); - } else { - go.walletHome(); - $timeout(function() { - notification.success( - gettextCatalog.getString('Success'), - gettextCatalog.getString('The wallet "{{walletName}}" was deleted', { - walletName: walletName - }) - ); - }); - } - }); - }; - - self.deleteWallet = function() { - var fc = profileService.focusedClient; - if (isCordova) { - navigator.notification.confirm( - delete_msg, - function(buttonIndex) { - if (buttonIndex == 1) { - doDeleteWallet(); - } - }, - confirm_msg, [accept_msg, cancel_msg] - ); - } else { - _modalDeleteWallet(); - } - }; - - self.copySecret = function(secret) { - if (isCordova) { - window.cordova.plugins.clipboard.copy(secret); - window.plugins.toast.showShortCenter(gettextCatalog.getString('Copied to clipboard')); - } - }; - - self.shareSecret = function(secret) { - if (isCordova) { - var message = gettextCatalog.getString('Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io', { - secret: secret - }); - window.plugins.socialsharing.share(message, gettextCatalog.getString('Invitation to share a Copay Wallet'), null, null); - } - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('createController', - function($scope, $rootScope, $timeout, $log, lodash, go, profileService, configService, gettext, ledger, trezor, platformInfo, derivationPathHelper, ongoingProcess) { - - var isChromeApp = platformInfo.isChromeApp; - var isCordova = platformInfo.isCordova; - var isDevel = platformInfo.isDevel; - - var self = this; - var defaults = configService.getDefaults(); - this.isWindowsPhoneApp = platformInfo.isWP && isCordova; - $scope.account = 1; - - /* For compressed keys, m*73 + n*34 <= 496 */ - var COPAYER_PAIR_LIMITS = { - 1: 1, - 2: 2, - 3: 3, - 4: 4, - 5: 4, - 6: 4, - 7: 3, - 8: 3, - 9: 2, - 10: 2, - 11: 1, - 12: 1, - }; - - var defaults = configService.getDefaults(); - $scope.bwsurl = defaults.bws.url; - $scope.derivationPath = derivationPathHelper.default; - - // ng-repeat defined number of times instead of repeating over array? - this.getNumber = function(num) { - return new Array(num); - } - - var updateRCSelect = function(n) { - $scope.totalCopayers = n; - var maxReq = COPAYER_PAIR_LIMITS[n]; - self.RCValues = lodash.range(1, maxReq + 1); - $scope.requiredCopayers = Math.min(parseInt(n / 2 + 1), maxReq); - }; - - var updateSeedSourceSelect = function(n) { - - self.seedOptions = [{ - id: 'new', - label: gettext('New Random Recovery Phrase'), - }, { - id: 'set', - label: gettext('Specify Recovery Phrase...'), - }]; - $scope.seedSource = self.seedOptions[0]; - - if (n > 1 && isChromeApp) - self.seedOptions.push({ - id: 'ledger', - label: 'Ledger', - }); - - if (isChromeApp || isDevel) { - self.seedOptions.push({ - id: 'trezor', - label: 'Trezor', - }); - } - }; - - this.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1); - $scope.totalCopayers = defaults.wallet.totalCopayers; - - this.setTotalCopayers = function(tc) { - updateRCSelect(tc); - updateSeedSourceSelect(tc); - self.seedSourceId = $scope.seedSource.id; - }; - - this.setSeedSource = function(src) { - self.seedSourceId = $scope.seedSource.id; - - $timeout(function() { - $rootScope.$apply(); - }); - }; - - this.create = function(form) { - if (form && form.$invalid) { - this.error = gettext('Please enter the required fields'); - return; - } - - var opts = { - m: $scope.requiredCopayers, - n: $scope.totalCopayers, - name: $scope.walletName, - myName: $scope.totalCopayers > 1 ? $scope.myName : null, - networkName: $scope.testnetEnabled ? 'testnet' : 'livenet', - bwsurl: $scope.bwsurl, - singleAddress: $scope.singleAddressEnabled, - walletPrivKey: $scope._walletPrivKey, // Only for testing - }; - var setSeed = self.seedSourceId == 'set'; - if (setSeed) { - - var words = $scope.privateKey || ''; - if (words.indexOf(' ') == -1 && words.indexOf('prv') == 1 && words.length > 108) { - opts.extendedPrivateKey = words; - } else { - opts.mnemonic = words; - } - opts.passphrase = $scope.passphrase; - - var pathData = derivationPathHelper.parse($scope.derivationPath); - if (!pathData) { - this.error = gettext('Invalid derivation path'); - return; - } - - opts.account = pathData.account; - opts.networkName = pathData.networkName; - opts.derivationStrategy = pathData.derivationStrategy; - - } else { - opts.passphrase = $scope.createPassphrase; - } - - if (setSeed && !opts.mnemonic && !opts.extendedPrivateKey) { - this.error = gettext('Please enter the wallet recovery phrase'); - return; - } - - if (self.seedSourceId == 'ledger' || self.seedSourceId == 'trezor') { - var account = $scope.account; - if (!account || account < 1) { - this.error = gettext('Invalid account number'); - return; - } - - if (self.seedSourceId == 'trezor') - account = account - 1; - - opts.account = account; - ongoingProcess.set('connecting' + self.seedSourceId, true); - - var src = self.seedSourceId == 'ledger' ? ledger : trezor; - - src.getInfoForNewWallet(opts.n > 1, account, function(err, lopts) { - ongoingProcess.set('connecting' + self.seedSourceId, false); - if (err) { - self.error = err; - $scope.$apply(); - return; - } - opts = lodash.assign(lopts, opts); - self._create(opts); - }); - } else { - self._create(opts); - } - }; - - this._create = function(opts) { - ongoingProcess.set('creatingWallet', true); - $timeout(function() { - - profileService.createWallet(opts, function(err) { - ongoingProcess.set('creatingWallet', false); - if (err) { - $log.warn(err); - self.error = err; - $timeout(function() { - $rootScope.$apply(); - }); - return; - } - if (self.seedSourceId == 'set') { - $timeout(function() { - $rootScope.$emit('Local/BackupDone'); - }, 1); - } - go.walletHome(); - - }); - }, 100); - } - - this.formFocus = function(what) { - if (!this.isWindowsPhoneApp) return - - if (what && what == 'my-name') { - this.hideWalletName = true; - this.hideTabs = true; - } else if (what && what == 'wallet-name') { - this.hideTabs = true; - } else { - this.hideWalletName = false; - this.hideTabs = false; - } - $timeout(function() { - $rootScope.$digest(); - }, 1); - }; - - $scope.$on("$destroy", function() { - $rootScope.hideWalletNavigation = false; - }); - - updateSeedSourceSelect(1); - self.setSeedSource(); - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('DevLoginController', function($scope, $rootScope, $routeParams, identityService) { - - var mail = $routeParams.mail; - var password = $routeParams.password; - - var form = {}; - form.email = {}; - form.password = {}; - form.email.$modelValue = mail; - form.password.$modelValue = password; - - identityService.open($scope, form); - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('disclaimerController', - function($scope, $rootScope, $timeout, $log, $ionicSideMenuDelegate, profileService, applicationService, gettextCatalog, uxLanguage, go, storageService, gettext, platformInfo, ongoingProcess) { - var self = this; - self.tries = 0; - var isCordova = platformInfo.isCordova; - - ongoingProcess.set('creatingWallet', true); - - var create = function(opts) { - opts = opts || {}; - $log.debug('Creating profile'); - - profileService.create(opts, function(err) { - if (err) { - $log.warn(err); - $scope.error = err; - $scope.$apply(); - - return $timeout(function() { - $log.warn('Retrying to create profile......'); - if (self.tries == 3) { - self.tries == 0; - return create({ - noWallet: true - }); - } else { - self.tries += 1; - return create(); - } - }, 3000); - }; - $scope.error = ""; - ongoingProcess.set('creatingWallet', false); - }); - }; - - this.init = function(opts) { - $ionicSideMenuDelegate.canDragContent(false); - self.lang = uxLanguage.currentLanguage; - - storageService.getProfile(function(err, profile) { - if (!profile) { - create(opts); - } else { - $log.info('There is already a profile'); - ongoingProcess.set('creatingWallet', false); - profileService.bindProfile(profile, function(err) { - if (!err || !err.message || !err.message.match('NONAGREEDDISCLAIMER')) { - $log.debug('Disclaimer already accepted at #disclaimer. Redirect to Wallet Home.'); - $ionicSideMenuDelegate.canDragContent(true); - go.walletHome(); - } - }); - } - }); - }; - - this.accept = function() { - profileService.setDisclaimerAccepted(function(err) { - if (err) $log.error(err); - else { - $ionicSideMenuDelegate.canDragContent(true); - $rootScope.$emit('disclaimerAccepted'); - go.walletHome(); - } - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('exportController', - function($rootScope, $scope, $timeout, $log, lodash, backupService, walletService, fingerprintService, configService, storageService, profileService, platformInfo, notification, go, gettext, gettextCatalog) { - var prevState; - var isWP = platformInfo.isWP; - var isAndroid = platformInfo.isAndroid; - var fc = profileService.focusedClient; - $scope.isEncrypted = fc.isPrivKeyEncrypted(); - $scope.isCordova = platformInfo.isCordova; - $scope.isSafari = platformInfo.isSafari; - $scope.error = null; - - $scope.init = function(state) { - $scope.supported = true; - $scope.exportQR = false; - $scope.noSignEnabled = false; - $scope.showAdvanced = false; - prevState = state || 'walletHome'; - - fingerprintService.check(fc, function(err) { - if (err) { - go.path(prevState); - return; - } - - handleEncryptedWallet(fc, function(err) { - if (err) { - go.path(prevState); - return; - } - - $scope.exportWalletInfo = encodeWalletInfo(); - $timeout(function() { - $scope.$apply(); - }, 1); - }); - }); - }; - - /* - EXPORT WITHOUT PRIVATE KEY - PENDING - - $scope.noSignEnabledChange = function() { - $scope.exportWalletInfo = encodeWalletInfo(); - $timeout(function() { - $scope.$apply(); - }, 1); - }; - */ - - $scope.$on('$destroy', function() { - walletService.lock(fc); - }); - - function handleEncryptedWallet(client, cb) { - if (!walletService.isEncrypted(client)) { - $scope.credentialsEncrypted = false; - return cb(); - } - - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - - function encodeWalletInfo() { - var c = fc.credentials; - var derivationPath = fc.credentials.getBaseAddressDerivationPath(); - var encodingType = { - mnemonic: 1, - xpriv: 2, - xpub: 3 - }; - var info; - - $scope.supported = (c.derivationStrategy == 'BIP44' && c.canSign()); - - if ($scope.supported) { - if (c.mnemonic) { - info = { - type: encodingType.mnemonic, - data: c.mnemonic, - } - } else { - info = { - type: encodingType.xpriv, - data: c.xPrivKey - } - } - } else { - /* - EXPORT WITHOUT PRIVATE KEY - PENDING - - info = { - type: encodingType.xpub, - data: c.xPubKey - } - */ - - return null; - } - - var code = info.type + '|' + info.data + '|' + c.network.toLowerCase() + '|' + derivationPath + '|' + (c.mnemonicHasPassphrase); - return code; - }; - - $scope.downloadWalletBackup = function() { - $scope.getAddressbook(function(err, localAddressBook) { - if (err) { - $scope.error = true; - return; - } - var opts = { - noSign: $scope.noSignEnabled, - addressBook: localAddressBook - }; - - backupService.walletDownload($scope.password, opts, function(err) { - if (err) { - $scope.error = true; - return; - } - notification.success(gettext('Success'), gettext('Encrypted export file saved')); - go.walletHome(); - }); - }); - }; - - $scope.getAddressbook = function(cb) { - storageService.getAddressbook(fc.credentials.network, function(err, addressBook) { - if (err) return cb(err); - - var localAddressBook = []; - try { - localAddressBook = JSON.parse(addressBook); - } catch (ex) { - $log.warn(ex); - } - - return cb(null, localAddressBook); - }); - }; - - $scope.getBackup = function(cb) { - $scope.getAddressbook(function(err, localAddressBook) { - if (err) { - $scope.error = true; - return cb(null); - } - var opts = { - noSign: $scope.noSignEnabled, - addressBook: localAddressBook - }; - - var ew = backupService.walletExport($scope.password, opts); - if (!ew) { - $scope.error = true; - } else { - $scope.error = false; - } - return cb(ew); - }); - }; - - $scope.viewWalletBackup = function() { - $timeout(function() { - $scope.getBackup(function(backup) { - var ew = backup; - if (!ew) return; - $scope.backupWalletPlainText = ew; - }); - }, 100); - }; - - $scope.copyWalletBackup = function() { - $scope.getBackup(function(backup) { - var ew = backup; - if (!ew) return; - window.cordova.plugins.clipboard.copy(ew); - window.plugins.toast.showShortCenter(gettextCatalog.getString('Copied to clipboard')); - }); - }; - - $scope.sendWalletBackup = function() { - var fc = profileService.focusedClient; - window.plugins.toast.showShortCenter(gettextCatalog.getString('Preparing backup...')); - var name = (fc.credentials.walletName || fc.credentials.walletId); - if (fc.alias) { - name = fc.alias + ' [' + name + ']'; - } - $scope.getBackup(function(backup) { - var ew = backup; - if (!ew) return; - - if ($scope.noSignEnabled) - name = name + '(No Private Key)'; - - var subject = 'Copay Wallet Backup: ' + name; - var body = 'Here is the encrypted backup of the wallet ' + name + ': \n\n' + ew + '\n\n To import this backup, copy all text between {...}, including the symbols {}'; - window.plugins.socialsharing.shareViaEmail( - body, - subject, - null, // TO: must be null or an array - null, // CC: must be null or an array - null, // BCC: must be null or an array - null, // FILES: can be null, a string, or an array - function() {}, - function() {} - ); - }); - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('glideraController', - function($rootScope, $scope, $timeout, $ionicModal, profileService, configService, storageService, glideraService, lodash, ongoingProcess) { - - this.getAuthenticateUrl = function() { - return glideraService.getOauthCodeUrl(); - }; - - this.submitOauthCode = function(code) { - var self = this; - var glideraTestnet = configService.getSync().glidera.testnet; - var network = glideraTestnet ? 'testnet' : 'livenet'; - ongoingProcess.set('connectingGlidera', true); - this.error = null; - $timeout(function() { - glideraService.getToken(code, function(err, data) { - ongoingProcess.set('connectingGlidera', false); - if (err) { - self.error = err; - $timeout(function() { - $scope.$apply(); - }, 100); - } else if (data && data.access_token) { - storageService.setGlideraToken(network, data.access_token, function() { - $scope.$emit('Local/GlideraUpdated', data.access_token); - $timeout(function() { - $scope.$apply(); - }, 100); - }); - } - }); - }, 100); - }; - - this.openTxModal = function(token, tx) { - var self = this; - - $scope.self = self; - $scope.tx = tx; - - glideraService.getTransaction(token, tx.transactionUuid, function(error, tx) { - $scope.tx = tx; - }); - - $ionicModal.fromTemplateUrl('views/modals/glidera-tx-details.html', { - scope: $scope, - backdropClickToClose: false, - hardwareBackButtonClose: false, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.glideraTxDetailsModal = modal; - $scope.glideraTxDetailsModal.show(); - }); - }; - - }); - -'use strict'; -angular.module('copayApp.controllers').controller('glideraUriController', - function($scope, $log, $stateParams, $timeout, profileService, configService, glideraService, storageService, go, ongoingProcess) { - - this.submitOauthCode = function(code) { - $log.debug('Glidera Oauth Code:' + code); - var self = this; - var glideraTestnet = configService.getSync().glidera.testnet; - var network = glideraTestnet ? 'testnet' : 'livenet'; - ongoingProcess.set('connectingGlidera', true); - this.error = null; - $timeout(function() { - glideraService.getToken(code, function(err, data) { - ongoingProcess.set('connectingGlidera', false); - if (err) { - self.error = err; - $timeout(function() { - $scope.$apply(); - }, 100); - } else if (data && data.access_token) { - storageService.setGlideraToken(network, data.access_token, function() { - $scope.$emit('Local/GlideraUpdated', data.access_token); - $timeout(function() { - go.path('glidera'); - $scope.$apply(); - }, 100); - }); - } - }); - }, 100); - }; - - this.checkCode = function() { - if ($stateParams.url) { - var match = $stateParams.url.match(/code=(.+)/); - if (match && match[1]) { - this.code = match[1]; - return this.submitOauthCode(this.code); - } - } - $log.error('Bad state: ' + JSON.stringify($stateParams)); - } - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('importController', - function($scope, $rootScope, $timeout, $log, profileService, configService, notification, go, sjcl, gettext, ledger, trezor, derivationPathHelper, platformInfo, bwcService, ongoingProcess) { - - var isChromeApp = platformInfo.isChromeApp; - var isDevel = platformInfo.isDevel; - var reader = new FileReader(); - var defaults = configService.getDefaults(); - var errors = bwcService.getErrors(); - $scope.dataFromQR = null; - $scope.bwsurl = defaults.bws.url; - $scope.derivationPath = derivationPathHelper.default; - $scope.account = 1; - $scope.importErr = false; - - var updateSeedSourceSelect = function() { - $scope.seedOptions = []; - - if (isChromeApp) { - $scope.seedOptions.push({ - id: 'ledger', - label: 'Ledger Hardware Wallet', - }); - } - - if (isChromeApp || isDevel) { - $scope.seedOptions.push({ - id: 'trezor', - label: 'Trezor Hardware Wallet', - }); - $scope.seedSource = $scope.seedOptions[0]; - } - }; - - $scope.processWalletInfo = function(code) { - if (!code) return; - - $scope.dataFromQR = null; - $scope.importErr = false; - $scope.error = null; - var parsedCode = code.split('|'); - - if (parsedCode.length != 5) { - /// Trying to import a malformed wallet export QR code - $scope.error = gettext('Incorrect code format'); - return; - } - - var info = { - type: parsedCode[0], - data: parsedCode[1], - network: parsedCode[2], - derivationPath: parsedCode[3], - hasPassphrase: parsedCode[4] == 'true' ? true : false - }; - - if (info.type == 1 && info.hasPassphrase) - $scope.error = gettext('Password required. Make sure to enter your password in advanced options'); - - $scope.derivationPath = info.derivationPath; - $scope.testnetEnabled = info.network == 'testnet' ? true : false; - - $timeout(function() { - $scope.words = null; - $scope.dataFromQR = info.data; - $rootScope.$apply(); - }, 1); - }; - - $scope.setType = function(type) { - $scope.type = type; - $scope.error = null; - $timeout(function() { - $rootScope.$apply(); - }, 1); - }; - - var _importBlob = function(str, opts) { - var str2, err; - try { - str2 = sjcl.decrypt($scope.password, str); - } catch (e) { - err = gettext('Could not decrypt file, check your password'); - $log.warn(e); - }; - - if (err) { - $scope.error = err; - $timeout(function() { - $rootScope.$apply(); - }); - return; - } - - ongoingProcess.set('importingWallet', true); - opts.compressed = null; - opts.password = null; - - $timeout(function() { - profileService.importWallet(str2, opts, function(err, walletId) { - ongoingProcess.set('importingWallet', false); - if (err) { - $scope.error = err; - } else { - $rootScope.$emit('Local/WalletImported', walletId); - notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); - go.walletHome(); - } - }); - }, 100); - }; - - var _importExtendedPrivateKey = function(xPrivKey, opts) { - ongoingProcess.set('importingWallet', true); - $timeout(function() { - profileService.importExtendedPrivateKey(xPrivKey, opts, function(err, walletId) { - ongoingProcess.set('importingWallet', false); - if (err) { - if (err instanceof errors.NOT_AUTHORIZED) { - $scope.importErr = true; - } else { - $scope.error = err; - } - return $timeout(function() { - $scope.$apply(); - }); - } - - $rootScope.$emit('Local/WalletImported', walletId); - notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); - go.walletHome(); - }); - }, 100); - }; - - /* - IMPORT FROM PUBLIC KEY - PENDING - - var _importExtendedPublicKey = function(xPubKey, opts) { - ongoingProcess.set('importingWallet', true); - $timeout(function() { - profileService.importExtendedPublicKey(opts, function(err, walletId) { - ongoingProcess.set('importingWallet', false); - if (err) { - $scope.error = err; - return $timeout(function() { - $scope.$apply(); - }); - } - $rootScope.$emit('Local/WalletImported', walletId); - notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); - go.walletHome(); - }); - }, 100); - }; - */ - - var _importMnemonic = function(words, opts) { - ongoingProcess.set('importingWallet', true); - - $timeout(function() { - profileService.importMnemonic(words, opts, function(err, walletId) { - ongoingProcess.set('importingWallet', false); - - if (err) { - if (err instanceof errors.NOT_AUTHORIZED) { - $scope.importErr = true; - } else { - $scope.error = err; - } - return $timeout(function() { - $scope.$apply(); - }); - } - - $rootScope.$emit('Local/WalletImported', walletId); - notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); - go.walletHome(); - }); - }, 100); - }; - - $scope.setDerivationPath = function() { - if ($scope.testnetEnabled) - $scope.derivationPath = derivationPathHelper.defaultTestnet; - else - $scope.derivationPath = derivationPathHelper.default; - }; - - $scope.getFile = function() { - // If we use onloadend, we need to check the readyState. - reader.onloadend = function(evt) { - if (evt.target.readyState == FileReader.DONE) { // DONE == 2 - var opts = {}; - opts.bwsurl = $scope.bwsurl; - _importBlob(evt.target.result, opts); - } - } - }; - - $scope.importBlob = function(form) { - if (form.$invalid) { - $scope.error = gettext('There is an error in the form'); - $timeout(function() { - $scope.$apply(); - }); - return; - } - - var backupFile = $scope.file; - var backupText = form.backupText.$modelValue; - var password = form.password.$modelValue; - - if (!backupFile && !backupText) { - $scope.error = gettext('Please, select your backup file'); - $timeout(function() { - $scope.$apply(); - }); - - return; - } - - if (backupFile) { - reader.readAsBinaryString(backupFile); - } else { - var opts = {}; - opts.bwsurl = $scope.bwsurl; - _importBlob(backupText, opts); - } - }; - - $scope.importMnemonic = function(form) { - if (form.$invalid) { - $scope.error = gettext('There is an error in the form'); - $timeout(function() { - $scope.$apply(); - }); - return; - } - - var opts = {}; - if ($scope.bwsurl) - opts.bwsurl = $scope.bwsurl; - - var pathData = derivationPathHelper.parse($scope.derivationPath); - if (!pathData) { - $scope.error = gettext('Invalid derivation path'); - return; - } - opts.account = pathData.account; - opts.networkName = pathData.networkName; - opts.derivationStrategy = pathData.derivationStrategy; - - var words = form.words.$modelValue || $scope.dataFromQR; - $scope.error = null; - - if (!words) { - $scope.error = gettext('Please enter the recovery phrase'); - } else if (words.indexOf('xprv') == 0 || words.indexOf('tprv') == 0) { - return _importExtendedPrivateKey(words, opts); - } else if (words.indexOf('xpub') == 0 || words.indexOf('tpuv') == 0) { - return _importExtendedPublicKey(words, opts); - } else { - var wordList = words.split(/[\u3000\s]+/); - - if ((wordList.length % 3) != 0) { - $scope.error = gettext('Wrong number of recovery words:') + wordList.length; - } - } - - if ($scope.error) { - $timeout(function() { - $scope.$apply(); - }); - return; - } - - var passphrase = form.passphrase.$modelValue; - opts.passphrase = form.passphrase.$modelValue || null; - - _importMnemonic(words, opts); - }; - - $scope.importTrezor = function(account, isMultisig) { - trezor.getInfoForNewWallet(isMultisig, account, function(err, lopts) { - ongoingProcess.clear(); - if (err) { - $scope.error = err; - $scope.$apply(); - return; - } - - lopts.externalSource = 'trezor'; - lopts.bwsurl = $scope.bwsurl; - ongoingProcess.set('importingWallet', true); - $log.debug('Import opts', lopts); - - profileService.importExtendedPublicKey(lopts, function(err, walletId) { - ongoingProcess.set('importingWallet', false); - if (err) { - $scope.error = err; - return $timeout(function() { - $scope.$apply(); - }); - } - $rootScope.$emit('Local/WalletImported', walletId); - notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); - go.walletHome(); - }); - }, 100); - }; - - $scope.importHW = function(form) { - if (form.$invalid || $scope.account < 0) { - $scope.error = gettext('There is an error in the form'); - $timeout(function() { - $scope.$apply(); - }); - return; - } - $scope.error = ''; - $scope.importErr = false; - - var account = +$scope.account; - - if ($scope.seedSourceId == 'trezor') { - if (account < 1) { - $scope.error = gettext('Invalid account number'); - return; - } - account = account - 1; - } - - switch ($scope.seedSourceId) { - case ('ledger'): - ongoingProcess.set('connectingledger', true); - $scope.importLedger(account); - break; - case ('trezor'): - ongoingProcess.set('connectingtrezor', true); - $scope.importTrezor(account, $scope.isMultisig); - break; - default: - throw ('Error: bad source id'); - }; - }; - - $scope.setSeedSource = function() { - - if (!$scope.seedSource) return; - $scope.seedSourceId = $scope.seedSource.id; - $timeout(function() { - $rootScope.$apply(); - }); - }; - - $scope.importLedger = function(account) { - ledger.getInfoForNewWallet(true, account, function(err, lopts) { - ongoingProcess.clear(); - if (err) { - $scope.error = err; - $scope.$apply(); - return; - } - - lopts.externalSource = 'ledger'; - lopts.bwsurl = $scope.bwsurl; - ongoingProcess.set('importingWallet', true); - $log.debug('Import opts', lopts); - - profileService.importExtendedPublicKey(lopts, function(err, walletId) { - ongoingProcess.set('importingWallet', false); - if (err) { - $scope.error = err; - return $timeout(function() { - $scope.$apply(); - }); - } - $rootScope.$emit('Local/WalletImported', walletId); - notification.success(gettext('Success'), gettext('Your wallet has been imported correctly')); - go.walletHome(); - }); - }, 100); - }; - - updateSeedSourceSelect(); - $scope.setSeedSource('new'); - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('indexController', function($rootScope, $scope, $log, $filter, $timeout, $ionicScrollDelegate, $ionicPopup, $ionicSideMenuDelegate, latestReleaseService, feeService, bwcService, pushNotificationsService, lodash, go, profileService, configService, rateService, storageService, addressService, gettext, gettextCatalog, amMoment, addonManager, bwcError, txFormatService, uxLanguage, glideraService, coinbaseService, platformInfo, addressbookService, openURLService, ongoingProcess) { - var self = this; - var SOFT_CONFIRMATION_LIMIT = 12; - var errors = bwcService.getErrors(); - var historyUpdateInProgress = {}; - var isChromeApp = platformInfo.isChromeApp; - var isCordova = platformInfo.isCordova; - var isNW = platformInfo.isNW; - - var ret = {}; - ret.isCordova = isCordova; - ret.isChromeApp = isChromeApp; - ret.isSafari = platformInfo.isSafari; - ret.isWindowsPhoneApp = platformInfo.isWP; - ret.historyShowLimit = 10; - ret.historyShowMoreLimit = 10; - ret.isSearching = false; - ret.prevState = 'walletHome'; - ret.physicalScreenWidth = ((window.innerWidth > 0) ? window.innerWidth : screen.width); - - // Only for testing - //storageService.checkQuota(); - - ret.menu = [{ - 'title': gettext('Receive'), - 'icon': { - false: 'icon-receive', - true: 'icon-receive-active' - }, - 'link': 'receive' - }, { - 'title': gettext('Activity'), - 'icon': { - false: 'icon-activity', - true: 'icon-activity-active' - }, - 'link': 'walletHome' - }, { - 'title': gettext('Send'), - 'icon': { - false: 'icon-send', - true: 'icon-send-active' - }, - 'link': 'send' - }]; - - ret.addonViews = addonManager.addonViews(); - ret.txTemplateUrl = addonManager.txTemplateUrl() || 'views/includes/transaction.html'; - - ret.tab = 'walletHome'; - var vanillaScope = ret; - - if (isNW) { - latestReleaseService.checkLatestRelease(function(err, newRelease) { - if (err) { - $log.warn(err); - return; - } - - if (newRelease) - $scope.newRelease = gettext('There is a new version of Copay. Please update'); - }); - } - - function strip(number) { - return (parseFloat(number.toPrecision(12))); - }; - - self.goHome = function() { - go.walletHome(); - }; - - self.allowRefresher = function() { - if ($ionicSideMenuDelegate.getOpenRatio() != 0) self.allowPullToRefresh = false; - } - - self.hideBalance = function() { - storageService.getHideBalanceFlag(self.walletId, function(err, shouldHideBalance) { - if (err) self.shouldHideBalance = false; - else self.shouldHideBalance = (shouldHideBalance == 'true') ? true : false; - }); - } - - self.onHold = function() { - self.shouldHideBalance = !self.shouldHideBalance; - storageService.setHideBalanceFlag(self.walletId, self.shouldHideBalance, function() {}); - } - - self.setWalletPreferencesTitle = function() { - return gettext("Wallet Preferences"); - } - - self.cleanInstance = function() { - $log.debug('Cleaning Index Instance'); - lodash.each(self, function(v, k) { - if (lodash.isFunction(v)) return; - // This are to prevent flicker in mobile: - if (k == 'hasProfile') return; - if (k == 'tab') return; - if (k == 'noFocusedWallet') return; - if (k == 'backgroundColor') return; - if (k == 'physicalScreenWidth') return; - if (k == 'loadingWallet') { - self.loadingWallet = true; - return; - } - if (!lodash.isUndefined(vanillaScope[k])) { - self[k] = vanillaScope[k]; - return; - } - - delete self[k]; - }); - }; - - self.setFocusedWallet = function() { - var fc = profileService.focusedClient; - if (!fc) return; - - self.cleanInstance(); - self.loadingWallet = true; - self.setSpendUnconfirmed(); - - $timeout(function() { - $rootScope.$apply(); - - self.hasProfile = true; - self.isSingleAddress = false; - self.noFocusedWallet = false; - self.updating = false; - - // Credentials Shortcuts - self.m = fc.credentials.m; - self.n = fc.credentials.n; - self.network = fc.credentials.network; - self.copayerId = fc.credentials.copayerId; - self.copayerName = fc.credentials.copayerName; - self.requiresMultipleSignatures = fc.credentials.m > 1; - self.isShared = fc.credentials.n > 1; - self.walletName = fc.credentials.walletName; - self.walletId = fc.credentials.walletId; - self.isComplete = fc.isComplete(); - self.canSign = fc.canSign(); - self.isPrivKeyExternal = fc.isPrivKeyExternal(); - self.isPrivKeyEncrypted = fc.isPrivKeyEncrypted(); - self.externalSource = fc.getPrivKeyExternalSourceName(); - self.account = fc.credentials.account; - self.incorrectDerivation = fc.keyDerivationOk === false; - - if (self.externalSource == 'trezor') - self.account++; - - self.txps = []; - self.copayers = []; - self.updateColor(); - self.updateAlias(); - self.setAddressbook(); - - self.initGlidera(); - self.initCoinbase(); - - self.hideBalance(); - - self.setCustomBWSFlag(); - - if (!self.isComplete) { - $log.debug('Wallet not complete BEFORE update... redirecting'); - go.path('copayers'); - } else { - if (go.is('copayers')) { - $log.debug('Wallet Complete BEFORE update... redirect to home'); - go.walletHome(); - } - } - - profileService.needsBackup(fc, function(needsBackup) { - self.needsBackup = needsBackup; - self.openWallet(function() { - if (!self.isComplete) { - $log.debug('Wallet not complete after update... redirecting'); - go.path('copayers'); - } else { - if (go.is('copayers')) { - $log.debug('Wallet Complete after update... redirect to home'); - go.walletHome(); - } - } - }); - }); - }); - }; - - self.setCustomBWSFlag = function() { - var defaults = configService.getDefaults(); - var config = configService.getSync(); - - self.usingCustomBWS = config.bwsFor && config.bwsFor[self.walletId] && (config.bwsFor[self.walletId] != defaults.bws.url); - }; - - - self.setTab = function(tab, reset, tries, switchState) { - tries = tries || 0; - - // check if the whole menu item passed - if (typeof tab == 'object') { - if (tab.open) { - if (tab.link) { - self.tab = tab.link; - } - tab.open(); - return; - } else { - return self.setTab(tab.link, reset, tries, switchState); - } - } - if (self.tab === tab && !reset) - return; - - if (!document.getElementById('menu-' + tab) && ++tries < 5) { - return $timeout(function() { - self.setTab(tab, reset, tries, switchState); - }, 300); - } - - if (!self.tab || !go.is('walletHome')) - self.tab = 'walletHome'; - - var changeTab = function() { - if (document.getElementById(self.tab)) { - document.getElementById(self.tab).className = 'tab-out tab-view ' + self.tab; - var old = document.getElementById('menu-' + self.tab); - if (old) { - old.className = ''; - } - } - - if (document.getElementById(tab)) { - document.getElementById(tab).className = 'tab-in tab-view ' + tab; - var newe = document.getElementById('menu-' + tab); - if (newe) { - newe.className = 'active'; - } - } - - self.tab = tab; - $rootScope.$emit('Local/TabChanged', tab); - }; - - if (switchState && !go.is('walletHome')) { - go.path('walletHome', function() { - changeTab(); - }); - return; - } - - changeTab(); - }; - - - - var _walletStatusHash = function(walletStatus) { - var bal; - if (walletStatus) { - bal = walletStatus.balance.totalAmount; - } else { - bal = self.totalBalanceSat; - } - return bal; - }; - - // TODO move this to wallet service - self.updateAll = function(opts, initStatusHash, tries) { - $scope.$broadcast('scroll.refreshComplete'); - tries = tries || 0; - opts = opts || {}; - var fc = profileService.focusedClient; - if (!fc) return; - - var walletId = fc.credentials.walletId - - if (opts.untilItChanges && lodash.isUndefined(initStatusHash)) { - initStatusHash = _walletStatusHash(); - $log.debug('Updating status until it changes. initStatusHash:' + initStatusHash) - } - - var get = function(cb) { - if (opts.walletStatus) - return cb(null, opts.walletStatus); - else { - self.updateError = false; - return fc.getStatus({ - twoStep: true - }, function(err, ret) { - if (err) { - self.updateError = bwcError.msg(err, gettext('Could not update Wallet')); - } else { - self.isSingleAddress = !!ret.wallet.singleAddress; - if (!opts.quiet) - self.updating = ret.wallet.scanStatus == 'running'; - } - return cb(err, ret); - }); - } - }; - - // If not untilItChanges...trigger history update now - if (opts.triggerTxUpdate && !opts.untilItChanges) { - $timeout(function() { - self.debounceUpdateHistory(); - }, 1); - } - - $timeout(function() { - - if (!opts.quiet) - self.updating = true; - - $log.debug('Updating Status:', fc.credentials.walletName, tries); - get(function(err, walletStatus) { - var currentStatusHash = _walletStatusHash(walletStatus); - $log.debug('Status update. hash:' + currentStatusHash + ' Try:' + tries); - if (!err && opts.untilItChanges && initStatusHash == currentStatusHash && tries < 7 && walletId == profileService.focusedClient.credentials.walletId) { - return $timeout(function() { - $log.debug('Retrying update... Try:' + tries) - return self.updateAll({ - walletStatus: null, - untilItChanges: true, - triggerTxUpdate: opts.triggerTxUpdate, - }, initStatusHash, ++tries); - }, 1400 * tries); - } - - if (walletId != profileService.focusedClient.credentials.walletId) - return; - - self.updating = false; - - if (err) { - self.handleError(err); - return; - } - $log.debug('Wallet Status:', walletStatus); - self.setPendingTxps(walletStatus.pendingTxps); - - // Status Shortcuts - self.lastUpdate = Date.now(); - self.walletName = walletStatus.wallet.name; - self.walletSecret = walletStatus.wallet.secret; - self.walletStatus = walletStatus.wallet.status; - self.walletScanStatus = walletStatus.wallet.scanStatus; - self.copayers = walletStatus.wallet.copayers; - self.preferences = walletStatus.preferences; - self.setBalance(walletStatus.balance); - self.otherWallets = lodash.filter(profileService.getWallets(self.network), function(w) { - return w.id != self.walletId; - }); - - // Notify external addons or plugins - $rootScope.$emit('Local/BalanceUpdated', walletStatus.balance); - $rootScope.$apply(); - - - if (opts.triggerTxUpdate && opts.untilItChanges) { - $timeout(function() { - self.debounceUpdateHistory(); - }, 1); - } else { - self.loadingWallet = false; - } - - if (opts.cb) return opts.cb(); - }); - }); - }; - - self.setSpendUnconfirmed = function(spendUnconfirmed) { - self.spendUnconfirmed = spendUnconfirmed || configService.getSync().wallet.spendUnconfirmed; - }; - - self.updateBalance = function() { - var fc = profileService.focusedClient; - $timeout(function() { - ongoingProcess.set('updatingBalance', true); - $log.debug('Updating Balance'); - fc.getBalance(function(err, balance) { - ongoingProcess.set('updatingBalance', false); - if (err) { - self.handleError(err); - return; - } - $log.debug('Wallet Balance:', balance); - self.setBalance(balance); - }); - }); - }; - - self.updatePendingTxps = function() { - var fc = profileService.focusedClient; - $timeout(function() { - self.updating = true; - $log.debug('Updating PendingTxps'); - fc.getTxProposals({}, function(err, txps) { - self.updating = false; - if (err) { - self.handleError(err); - } else { - $log.debug('Wallet PendingTxps:', txps); - self.setPendingTxps(txps); - } - $rootScope.$apply(); - }); - }); - }; - - // This handles errors from BWS/index which normally - // trigger from async events (like updates). - // Debounce function avoids multiple popups - var _handleError = function(err) { - $log.warn('Client ERROR: ', err); - if (err instanceof errors.NOT_AUTHORIZED) { - self.notAuthorized = true; - go.walletHome(); - } else if (err instanceof errors.NOT_FOUND) { - self.showErrorPopup(gettext('Could not access Wallet Service: Not found')); - } else { - var msg = "" - $scope.$emit('Local/ClientError', (err.error ? err.error : err)); - var msg = bwcError.msg(err, gettext('Error at Wallet Service')); - self.showErrorPopup(msg); - } - }; - - self.handleError = lodash.debounce(_handleError, 1000); - - self.openWallet = function(cb) { - var fc = profileService.focusedClient; - $timeout(function() { - $rootScope.$apply(); - self.updating = true; - self.updateError = false; - fc.openWallet(function(err, walletStatus) { - self.updating = false; - if (err) { - self.updateError = true; - self.handleError(err); - return; - } - $log.debug('Wallet Opened'); - - self.updateAll(lodash.isObject(walletStatus) ? { - walletStatus: walletStatus, - cb: cb, - } : { - cb: cb - }); - $rootScope.$apply(); - }); - }); - }; - - self.setPendingTxps = function(txps) { - self.pendingTxProposalsCountForUs = 0; - var now = Math.floor(Date.now() / 1000); - - /* Uncomment to test multiple outputs */ - /* - var txp = { - message: 'test multi-output', - fee: 1000, - createdOn: new Date() / 1000, - outputs: [] - }; - function addOutput(n) { - txp.outputs.push({ - amount: 600, - toAddress: '2N8bhEwbKtMvR2jqMRcTCQqzHP6zXGToXcK', - message: 'output #' + (Number(n) + 1) - }); - }; - lodash.times(150, addOutput); - txps.push(txp); - */ - - lodash.each(txps, function(tx) { - - tx = txFormatService.processTx(tx); - - // no future transactions... - if (tx.createdOn > now) - tx.createdOn = now; - - var action = lodash.find(tx.actions, { - copayerId: self.copayerId - }); - - if (!action && tx.status == 'pending') { - tx.pendingForUs = true; - } - - if (action && action.type == 'accept') { - tx.statusForUs = 'accepted'; - } else if (action && action.type == 'reject') { - tx.statusForUs = 'rejected'; - } else { - tx.statusForUs = 'pending'; - } - - if (!tx.deleteLockTime) - tx.canBeRemoved = true; - - if (tx.creatorId != self.copayerId) { - self.pendingTxProposalsCountForUs = self.pendingTxProposalsCountForUs + 1; - } - addonManager.formatPendingTxp(tx); - }); - self.txps = txps; - }; - - var SAFE_CONFIRMATIONS = 6; - - self.processNewTxs = function(txs) { - var config = configService.getSync().wallet.settings; - var now = Math.floor(Date.now() / 1000); - var txHistoryUnique = {}; - var ret = []; - self.hasUnsafeConfirmed = false; - - lodash.each(txs, function(tx) { - tx = txFormatService.processTx(tx); - - // no future transactions... - if (tx.time > now) - tx.time = now; - - if (tx.confirmations >= SAFE_CONFIRMATIONS) { - tx.safeConfirmed = SAFE_CONFIRMATIONS + '+'; - } else { - tx.safeConfirmed = false; - self.hasUnsafeConfirmed = true; - } - - if (tx.note) { - delete tx.note.encryptedEditedByName; - delete tx.note.encryptedBody; - } - - if (!txHistoryUnique[tx.txid]) { - ret.push(tx); - txHistoryUnique[tx.txid] = true; - } else { - $log.debug('Ignoring duplicate TX in history: ' + tx.txid) - } - }); - - return ret; - }; - - self.updateAlias = function() { - var config = configService.getSync(); - config.aliasFor = config.aliasFor || {}; - self.alias = config.aliasFor[self.walletId]; - var fc = profileService.focusedClient; - fc.alias = self.alias; - }; - - self.updateColor = function() { - var config = configService.getSync(); - config.colorFor = config.colorFor || {}; - self.backgroundColor = config.colorFor[self.walletId] || '#4A90E2'; - var fc = profileService.focusedClient; - fc.backgroundColor = self.backgroundColor; - if (isCordova && StatusBar.isVisible) { - StatusBar.backgroundColorByHexString(fc.backgroundColor); - } - }; - - self.setBalance = function(balance) { - if (!balance) return; - var config = configService.getSync().wallet.settings; - var COIN = 1e8; - - - // Address with Balance - self.balanceByAddress = balance.byAddress; - - // Spend unconfirmed funds - if (self.spendUnconfirmed) { - self.totalBalanceSat = balance.totalAmount; - self.lockedBalanceSat = balance.lockedAmount; - self.availableBalanceSat = balance.availableAmount; - self.totalBytesToSendMax = balance.totalBytesToSendMax; - self.pendingAmount = null; - } else { - self.totalBalanceSat = balance.totalConfirmedAmount; - self.lockedBalanceSat = balance.lockedConfirmedAmount; - self.availableBalanceSat = balance.availableConfirmedAmount; - self.totalBytesToSendMax = balance.totalBytesToSendConfirmedMax; - self.pendingAmount = balance.totalAmount - balance.totalConfirmedAmount; - } - - // Selected unit - self.unitToSatoshi = config.unitToSatoshi; - self.satToUnit = 1 / self.unitToSatoshi; - self.unitName = config.unitName; - - //STR - self.totalBalanceStr = profileService.formatAmount(self.totalBalanceSat) + ' ' + self.unitName; - self.lockedBalanceStr = profileService.formatAmount(self.lockedBalanceSat) + ' ' + self.unitName; - self.availableBalanceStr = profileService.formatAmount(self.availableBalanceSat) + ' ' + self.unitName; - - if (self.pendingAmount) { - self.pendingAmountStr = profileService.formatAmount(self.pendingAmount) + ' ' + self.unitName; - } else { - self.pendingAmountStr = null; - } - - self.alternativeName = config.alternativeName; - self.alternativeIsoCode = config.alternativeIsoCode; - - // Check address - addressService.isUsed(self.walletId, balance.byAddress, function(err, used) { - if (used) { - $log.debug('Address used. Creating new'); - $rootScope.$emit('Local/AddressIsUsed'); - } - }); - - rateService.whenAvailable(function() { - - var totalBalanceAlternative = rateService.toFiat(self.totalBalanceSat, self.alternativeIsoCode); - var lockedBalanceAlternative = rateService.toFiat(self.lockedBalanceSat, self.alternativeIsoCode); - var alternativeConversionRate = rateService.toFiat(100000000, self.alternativeIsoCode); - - self.totalBalanceAlternative = $filter('formatFiatAmount')(totalBalanceAlternative); - self.lockedBalanceAlternative = $filter('formatFiatAmount')(lockedBalanceAlternative); - self.alternativeConversionRate = $filter('formatFiatAmount')(alternativeConversionRate); - - self.alternativeBalanceAvailable = true; - - self.isRateAvailable = true; - $rootScope.$apply(); - }); - - if (!rateService.isAvailable()) { - $rootScope.$apply(); - } - }; - - self.removeAndMarkSoftConfirmedTx = function(txs) { - return lodash.filter(txs, function(tx) { - if (tx.confirmations >= SOFT_CONFIRMATION_LIMIT) - return tx; - tx.recent = true; - }); - } - - self.getSavedTxs = function(walletId, cb) { - - storageService.getTxHistory(walletId, function(err, txs) { - if (err) return cb(err); - - var localTxs = []; - - if (!txs) { - return cb(null, localTxs); - } - - try { - localTxs = JSON.parse(txs); - } catch (ex) { - $log.warn(ex); - } - return cb(null, lodash.compact(localTxs)); - }); - } - - self.updateLocalTxHistory = function(client, cb) { - var FIRST_LIMIT = 5; - var LIMIT = 50; - var requestLimit = FIRST_LIMIT; - var walletId = client.credentials.walletId; - var config = configService.getSync().wallet.settings; - - var fixTxsUnit = function(txs) { - if (!txs || !txs[0] || !txs[0].amountStr) return; - - var cacheUnit = txs[0].amountStr.split(' ')[1]; - - if (cacheUnit == config.unitName) - return; - - var name = ' ' + config.unitName; - - $log.debug('Fixing Tx Cache Unit to:' + name) - lodash.each(txs, function(tx) { - - tx.amountStr = profileService.formatAmount(tx.amount) + name; - tx.feeStr = profileService.formatAmount(tx.fees) + name; - }); - }; - - self.getSavedTxs(walletId, function(err, txsFromLocal) { - if (err) return cb(err); - - fixTxsUnit(txsFromLocal); - - var confirmedTxs = self.removeAndMarkSoftConfirmedTx(txsFromLocal); - var endingTxid = confirmedTxs[0] ? confirmedTxs[0].txid : null; - var endingTs = confirmedTxs[0] ? confirmedTxs[0].time : null; - - - // First update - if (walletId == profileService.focusedClient.credentials.walletId) { - self.completeHistory = txsFromLocal; - self.setCompactTxHistory(); - } - - if (historyUpdateInProgress[walletId]) - return; - - historyUpdateInProgress[walletId] = true; - - function getNewTxs(newTxs, skip, i_cb) { - self.getTxsFromServer(client, skip, endingTxid, requestLimit, function(err, res, shouldContinue) { - if (err) return i_cb(err); - - newTxs = newTxs.concat(lodash.compact(res)); - skip = skip + requestLimit; - - $log.debug('Syncing TXs. Got:' + newTxs.length + ' Skip:' + skip, ' EndingTxid:', endingTxid, ' Continue:', shouldContinue); - - if (!shouldContinue) { - newTxs = self.processNewTxs(newTxs); - $log.debug('Finished Sync: New / soft confirmed Txs: ' + newTxs.length); - return i_cb(null, newTxs); - } - - requestLimit = LIMIT; - getNewTxs(newTxs, skip, i_cb); - - // Progress update - if (walletId == profileService.focusedClient.credentials.walletId) { - self.txProgress = newTxs.length; - if (self.completeHistory < FIRST_LIMIT && txsFromLocal.length == 0) { - $log.debug('Showing partial history'); - var newHistory = self.processNewTxs(newTxs); - newHistory = lodash.compact(newHistory.concat(confirmedTxs)); - self.completeHistory = newHistory; - self.setCompactTxHistory(); - } - $timeout(function() { - $rootScope.$apply(); - }); - } - }); - }; - - getNewTxs([], 0, function(err, txs) { - if (err) return cb(err); - - var newHistory = lodash.uniq(lodash.compact(txs.concat(confirmedTxs)), function(x) { - return x.txid; - }); - - - function updateNotes(cb2) { - if (!endingTs) return cb2(); - - $log.debug('Syncing notes from: ' + endingTs); - client.getTxNotes({ - minTs: endingTs - }, function(err, notes) { - if (err) { - $log.warn(err); - return cb2(); - }; - lodash.each(notes, function(note) { - $log.debug('Note for ' + note.txid); - lodash.each(newHistory, function(tx) { - if (tx.txid == note.txid) { - $log.debug('...updating note for ' + note.txid); - tx.note = note; - } - }); - }); - return cb2(); - }); - } - - updateNotes(function() { - var historyToSave = JSON.stringify(newHistory); - - lodash.each(txs, function(tx) { - tx.recent = true; - }) - - $log.debug('Tx History synced. Total Txs: ' + newHistory.length); - - // Final update - if (walletId == profileService.focusedClient.credentials.walletId) { - self.completeHistory = newHistory; - self.setCompactTxHistory(); - } - - return storageService.setTxHistory(historyToSave, walletId, function() { - $log.debug('Tx History saved.'); - - return cb(); - }); - }); - }); - }); - } - - self.showMore = function() { - $timeout(function() { - if (self.isSearching) { - self.txHistorySearchResults = self.result.slice(0, self.nextTxHistory); - $log.debug('Total txs: ', self.txHistorySearchResults.length + '/' + self.result.length); - if (self.txHistorySearchResults.length >= self.result.length) - self.historyShowMore = false; - } else { - self.txHistory = self.completeHistory.slice(0, self.nextTxHistory); - $log.debug('Total txs: ', self.txHistory.length + '/' + self.completeHistory.length); - if (self.txHistory.length >= self.completeHistory.length) - self.historyShowMore = false; - } - self.nextTxHistory += self.historyShowMoreLimit; - $scope.$broadcast('scroll.infiniteScrollComplete'); - }, 100); - }; - - self.startSearch = function() { - self.isSearching = true; - self.txHistorySearchResults = []; - self.result = []; - self.historyShowMore = false; - self.nextTxHistory = self.historyShowMoreLimit; - } - - self.cancelSearch = function() { - self.isSearching = false; - self.result = []; - self.setCompactTxHistory(); - } - - self.updateSearchInput = function(search) { - self.search = search; - if (isCordova) - window.plugins.toast.hide(); - self.throttleSearch(); - $ionicScrollDelegate.resize(); - } - - self.throttleSearch = lodash.throttle(function() { - - function filter(search) { - self.result = []; - - function computeSearchableString(tx) { - var addrbook = ''; - if (tx.addressTo && self.addressbook && self.addressbook[tx.addressTo]) addrbook = self.addressbook[tx.addressTo] || ''; - var searchableDate = computeSearchableDate(new Date(tx.time * 1000)); - var message = tx.message ? tx.message : ''; - var comment = tx.note ? tx.note.body : ''; - var addressTo = tx.addressTo ? tx.addressTo : ''; - return ((tx.amountStr + message + addressTo + addrbook + searchableDate + comment).toString()).toLowerCase(); - } - - function computeSearchableDate(date) { - var day = ('0' + date.getDate()).slice(-2).toString(); - var month = ('0' + (date.getMonth() + 1)).slice(-2).toString(); - var year = date.getFullYear(); - return [month, day, year].join('/'); - }; - - if (lodash.isEmpty(search)) { - self.historyShowMore = false; - return []; - } - self.result = lodash.filter(self.completeHistory, function(tx) { - if (!tx.searcheableString) tx.searcheableString = computeSearchableString(tx); - return lodash.includes(tx.searcheableString, search.toLowerCase()); - }); - - if (self.result.length > self.historyShowLimit) self.historyShowMore = true; - else self.historyShowMore = false; - - return self.result; - }; - - self.txHistorySearchResults = filter(self.search).slice(0, self.historyShowLimit); - if (isCordova) - window.plugins.toast.showShortBottom(gettextCatalog.getString('Matches: ' + self.result.length)); - - $timeout(function() { - $rootScope.$apply(); - }); - - }, 1000); - - self.getTxsFromServer = function(client, skip, endingTxid, limit, cb) { - var res = []; - - client.getTxHistory({ - skip: skip, - limit: limit - }, function(err, txsFromServer) { - if (err) return cb(err); - - if (!txsFromServer.length) - return cb(); - - var res = lodash.takeWhile(txsFromServer, function(tx) { - return tx.txid != endingTxid; - }); - - return cb(null, res, res.length == limit); - }); - }; - - self.updateHistory = function() { - var fc = profileService.focusedClient; - if (!fc) return; - var walletId = fc.credentials.walletId; - - if (!fc.isComplete()) { - return; - } - - $log.debug('Updating Transaction History'); - self.txHistoryError = false; - self.updatingTxHistory = true; - - $timeout(function() { - self.updateLocalTxHistory(fc, function(err) { - historyUpdateInProgress[walletId] = self.updatingTxHistory = false; - self.loadingWallet = false; - self.txProgress = 0; - if (err) - self.txHistoryError = true; - - $timeout(function() { - self.newTx = false - }, 1000); - - $rootScope.$apply(); - }); - }); - }; - - self.setCompactTxHistory = function() { - self.isSearching = false; - self.nextTxHistory = self.historyShowMoreLimit; - self.txHistory = self.completeHistory ? self.completeHistory.slice(0, self.historyShowLimit) : null; - self.historyShowMore = self.completeHistory ? self.completeHistory.length > self.historyShowLimit : null; - }; - - self.debounceUpdateHistory = lodash.debounce(function() { - self.updateHistory(); - }, 1000); - - self.throttledUpdateHistory = lodash.throttle(function() { - self.updateHistory(); - }, 5000); - - self.showErrorPopup = function(msg, cb) { - $log.warn('Showing err popup:' + msg); - - function openErrorPopup(msg, cb) { - $scope.msg = msg; - - self.errorPopup = $ionicPopup.show({ - templateUrl: 'views/includes/alert.html', - scope: $scope, - }); - - $scope.close = function() { - return cb(); - }; - } - - openErrorPopup(msg, function() { - self.errorPopup.close(); - if (cb) return cb(); - }); - }; - - self.recreate = function(cb) { - var fc = profileService.focusedClient; - ongoingProcess.set('recreating', true); - fc.recreateWallet(function(err) { - self.notAuthorized = false; - ongoingProcess.set('recreating', false); - - if (err) { - self.handleError(err); - $rootScope.$apply(); - return; - } - - profileService.bindWalletClient(fc, { - force: true - }); - self.startScan(self.walletId); - }); - }; - - self.toggleLeftMenu = function() { - profileService.isDisclaimerAccepted(function(val) { - if (val) go.toggleLeftMenu(); - else - $log.debug('Disclaimer not accepted, cannot open menu'); - }); - }; - - self.retryScan = function() { - var self = this; - self.startScan(self.walletId); - } - - self.startScan = function(walletId) { - $log.debug('Scanning wallet ' + walletId); - var c = profileService.walletClients[walletId]; - if (!c.isComplete()) return; - - if (self.walletId == walletId) - self.updating = true; - - c.startScan({ - includeCopayerBranches: true, - }, function(err) { - if (err && self.walletId == walletId) { - self.updating = false; - self.handleError(err); - $rootScope.$apply(); - } - }); - }; - - self.initGlidera = function(accessToken) { - self.glideraEnabled = configService.getSync().glidera.enabled; - self.glideraTestnet = configService.getSync().glidera.testnet; - var network = self.glideraTestnet ? 'testnet' : 'livenet'; - - self.glideraToken = null; - self.glideraError = null; - self.glideraPermissions = null; - self.glideraEmail = null; - self.glideraPersonalInfo = null; - self.glideraTxs = null; - self.glideraStatus = null; - - if (!self.glideraEnabled) return; - - glideraService.setCredentials(network); - - var getToken = function(cb) { - if (accessToken) { - cb(null, accessToken); - } else { - storageService.getGlideraToken(network, cb); - } - }; - - getToken(function(err, accessToken) { - if (err || !accessToken) return; - else { - glideraService.getAccessTokenPermissions(accessToken, function(err, p) { - if (err) { - self.glideraError = err; - } else { - self.glideraToken = accessToken; - self.glideraPermissions = p; - self.updateGlidera({ - fullUpdate: true - }); - } - }); - } - }); - }; - - self.updateGlidera = function(opts) { - if (!self.glideraToken || !self.glideraPermissions) return; - var accessToken = self.glideraToken; - var permissions = self.glideraPermissions; - - opts = opts || {}; - - glideraService.getStatus(accessToken, function(err, data) { - self.glideraStatus = data; - }); - - glideraService.getLimits(accessToken, function(err, limits) { - self.glideraLimits = limits; - }); - - if (permissions.transaction_history) { - glideraService.getTransactions(accessToken, function(err, data) { - self.glideraTxs = data; - }); - } - - if (permissions.view_email_address && opts.fullUpdate) { - glideraService.getEmail(accessToken, function(err, data) { - self.glideraEmail = data.email; - }); - } - if (permissions.personal_info && opts.fullUpdate) { - glideraService.getPersonalInfo(accessToken, function(err, data) { - self.glideraPersonalInfo = data; - }); - } - - }; - - self.initCoinbase = function(accessToken) { - self.coinbaseEnabled = configService.getSync().coinbase.enabled; - self.coinbaseTestnet = configService.getSync().coinbase.testnet; - var network = self.coinbaseTestnet ? 'testnet' : 'livenet'; - - self.coinbaseToken = null; - self.coinbaseError = null; - self.coinbasePermissions = null; - self.coinbaseEmail = null; - self.coinbasePersonalInfo = null; - self.coinbaseTxs = null; - self.coinbaseStatus = null; - - if (!self.coinbaseEnabled) return; - - coinbaseService.setCredentials(network); - - var getToken = function(cb) { - if (accessToken) { - cb(null, accessToken); - } else { - storageService.getCoinbaseToken(network, cb); - } - }; - - getToken(function(err, accessToken) { - if (err || !accessToken) return; - else { - coinbaseService.getAccounts(accessToken, function(err, a) { - if (err) { - self.coinbaseError = err; - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - } - } else { - self.coinbaseToken = accessToken; - lodash.each(a.data, function(account) { - if (account.primary && account.type == 'wallet') { - self.coinbaseAccount = account; - self.updateCoinbase(); - } - }); - } - }); - } - }); - }; - - self.updateCoinbase = lodash.debounce(function(opts) { - if (!self.coinbaseToken || !self.coinbaseAccount) return; - var accessToken = self.coinbaseToken; - var accountId = self.coinbaseAccount.id; - - opts = opts || {}; - - if (opts.updateAccount) { - coinbaseService.getAccount(accessToken, accountId, function(err, a) { - if (err) { - self.coinbaseError = err; - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - } - return; - } - self.coinbaseAccount = a.data; - }); - } - - coinbaseService.getCurrentUser(accessToken, function(err, u) { - if (err) { - self.coinbaseError = err; - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - } - return; - } - self.coinbaseUser = u.data; - }); - - coinbaseService.getPendingTransactions(function(err, txs) { - self.coinbasePendingTransactions = lodash.isEmpty(txs) ? null : txs; - lodash.forEach(txs, function(dataFromStorage, txId) { - if ((dataFromStorage.type == 'sell' && dataFromStorage.status == 'completed') || - (dataFromStorage.type == 'buy' && dataFromStorage.status == 'completed') || - dataFromStorage.status == 'error' || - (dataFromStorage.type == 'send' && dataFromStorage.status == 'completed')) return; - coinbaseService.getTransaction(accessToken, accountId, txId, function(err, tx) { - if (err) { - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - return; - } - coinbaseService.savePendingTransaction(dataFromStorage, { - status: 'error', - error: err - }, function(err) { - if (err) $log.debug(err); - }); - return; - } - _updateCoinbasePendingTransactions(dataFromStorage, tx.data); - self.coinbasePendingTransactions[txId] = dataFromStorage; - if (tx.data.type == 'send' && tx.data.status == 'completed' && tx.data.from) { - coinbaseService.sellPrice(accessToken, dataFromStorage.sell_price_currency, function(err, s) { - if (err) { - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - return; - } - coinbaseService.savePendingTransaction(dataFromStorage, { - status: 'error', - error: err - }, function(err) { - if (err) $log.debug(err); - }); - return; - } - var newSellPrice = s.data.amount; - var variance = Math.abs((newSellPrice - dataFromStorage.sell_price_amount) / dataFromStorage.sell_price_amount * 100); - if (variance < dataFromStorage.price_sensitivity.value) { - self.sellPending(tx.data); - } else { - var error = { - errors: [{ - message: 'Price falls over the selected percentage' - }] - }; - coinbaseService.savePendingTransaction(dataFromStorage, { - status: 'error', - error: error - }, function(err) { - if (err) $log.debug(err); - }); - } - }); - } else if (tx.data.type == 'buy' && tx.data.status == 'completed' && tx.data.buy) { - self.sendToCopay(dataFromStorage); - } else { - coinbaseService.savePendingTransaction(dataFromStorage, {}, function(err) { - if (err) $log.debug(err); - }); - } - }); - }); - }); - - }, 1000); - - var _updateCoinbasePendingTransactions = function(obj /*, …*/ ) { - for (var i = 1; i < arguments.length; i++) { - for (var prop in arguments[i]) { - var val = arguments[i][prop]; - if (typeof val == "object") - _updateCoinbasePendingTransactions(obj[prop], val); - else - obj[prop] = val ? val : obj[prop]; - } - } - return obj; - }; - - self.refreshCoinbaseToken = function() { - var network = self.coinbaseTestnet ? 'testnet' : 'livenet'; - storageService.getCoinbaseRefreshToken(network, function(err, refreshToken) { - if (!refreshToken) return; - coinbaseService.refreshToken(refreshToken, function(err, data) { - if (err) { - self.coinbaseError = err; - } else if (data && data.access_token && data.refresh_token) { - storageService.setCoinbaseToken(network, data.access_token, function() { - storageService.setCoinbaseRefreshToken(network, data.refresh_token, function() { - $timeout(function() { - self.initCoinbase(data.access_token); - }, 100); - }); - }); - } - }); - }); - }; - - self.sendToCopay = function(tx) { - if (!tx) return; - var data = { - to: tx.toAddr, - amount: tx.amount.amount, - currency: tx.amount.currency, - description: 'To Copay Wallet' - }; - coinbaseService.sendTo(self.coinbaseToken, self.coinbaseAccount.id, data, function(err, res) { - if (err) { - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - return; - } - coinbaseService.savePendingTransaction(tx, { - status: 'error', - error: err - }, function(err) { - if (err) $log.debug(err); - }); - } else { - if (!res.data.id) { - coinbaseService.savePendingTransaction(tx, { - status: 'error', - error: err - }, function(err) { - if (err) $log.debug(err); - }); - return; - } - coinbaseService.getTransaction(self.coinbaseToken, self.coinbaseAccount.id, res.data.id, function(err, sendTx) { - coinbaseService.savePendingTransaction(tx, { - remove: true - }, function(err) { - coinbaseService.savePendingTransaction(sendTx.data, {}, function(err) { - $timeout(function() { - self.updateCoinbase({ - updateAccount: true - }); - }, 1000); - }); - }); - }); - } - }); - }; - - self.sellPending = function(tx) { - if (!tx) return; - var data = tx.amount; - data['commit'] = true; - coinbaseService.sellRequest(self.coinbaseToken, self.coinbaseAccount.id, data, function(err, res) { - if (err) { - if (err.errors[0] && err.errors[0].id == 'expired_token') { - self.refreshCoinbaseToken(); - return; - } - coinbaseService.savePendingTransaction(tx, { - status: 'error', - error: err - }, function(err) { - if (err) $log.debug(err); - }); - } else { - if (!res.data.transaction) { - coinbaseService.savePendingTransaction(tx, { - status: 'error', - error: err - }, function(err) { - if (err) $log.debug(err); - }); - return; - } - coinbaseService.savePendingTransaction(tx, { - remove: true - }, function(err) { - coinbaseService.getTransaction(self.coinbaseToken, self.coinbaseAccount.id, res.data.transaction.id, function(err, updatedTx) { - coinbaseService.savePendingTransaction(updatedTx.data, {}, function(err) { - if (err) $log.debug(err); - $timeout(function() { - self.updateCoinbase({ - updateAccount: true - }); - }, 1000); - }); - }); - }); - } - }); - }; - - self.isInFocus = function(walletId) { - var fc = profileService.focusedClient; - return fc && fc.credentials.walletId == walletId; - }; - - self.setAddressbook = function(ab) { - if (ab) { - self.addressbook = ab; - return; - } - - addressbookService.list(function(err, ab) { - if (err) { - $log.error('Error getting the addressbook'); - return; - } - self.addressbook = ab; - }); - }; - - $rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from, fromParams) { - self.prevState = from.name || 'walletHome'; - self.tab = 'walletHome'; - }); - - $rootScope.$on('Local/ValidatingWalletEnded', function(ev, walletId, isOK) { - - if (self.isInFocus(walletId)) { - // NOTE: If the user changed the wallet, the flag is already turn off. - self.incorrectDerivation = isOK === false; - } - }); - - $rootScope.$on('Local/ClearHistory', function(event) { - $log.debug('The wallet transaction history has been deleted'); - self.txHistory = self.completeHistory = self.txHistorySearchResults = []; - self.debounceUpdateHistory(); - }); - - $rootScope.$on('Local/AddressbookUpdated', function(event, ab) { - self.setAddressbook(ab); - }); - - // UX event handlers - $rootScope.$on('Local/ColorUpdated', function(event) { - self.updateColor(); - $timeout(function() { - $rootScope.$apply(); - }); - }); - - $rootScope.$on('Local/AliasUpdated', function(event) { - self.updateAlias(); - $timeout(function() { - $rootScope.$apply(); - }); - }); - - $rootScope.$on('Local/SpendUnconfirmedUpdated', function(event, spendUnconfirmed) { - self.setSpendUnconfirmed(spendUnconfirmed); - self.updateAll(); - }); - - $rootScope.$on('Local/GlideraUpdated', function(event, accessToken) { - self.initGlidera(accessToken); - }); - - $rootScope.$on('Local/CoinbaseUpdated', function(event, accessToken) { - self.initCoinbase(accessToken); - }); - - $rootScope.$on('Local/GlideraTx', function(event, accessToken, permissions) { - self.updateGlidera(); - }); - - $rootScope.$on('Local/CoinbaseTx', function(event) { - self.updateCoinbase({ - updateAccount: true - }); - }); - - $rootScope.$on('Local/GlideraError', function(event) { - self.debouncedUpdate(); - }); - - $rootScope.$on('Local/UnitSettingUpdated', function(event) { - self.updateAll({ - triggerTxUpdate: true, - }); - }); - - $rootScope.$on('Local/WalletCompleted', function(event, walletId) { - if (self.isInFocus(walletId)) { - // reset main wallet variables - self.setFocusedWallet(); - go.walletHome(); - } - }); - - self.debouncedUpdate = function() { - var now = Date.now(); - var oneHr = 1000 * 60 * 60; - - if (!self.lastUpdate || (now - self.lastUpdate) > oneHr) { - self.updateAll({ - quiet: true, - triggerTxUpdate: true - }); - } - }; - - $rootScope.$on('Local/Resume', function(event) { - $log.debug('### Resume event'); - profileService.isDisclaimerAccepted(function(v) { - if (!v) { - $log.debug('Disclaimer not accepted, resume to home'); - go.path('disclaimer'); - } - }); - self.debouncedUpdate(); - }); - - $rootScope.$on('Local/BackupDone', function(event, walletId) { - self.needsBackup = false; - $log.debug('Backup done'); - storageService.setBackupFlag(walletId || self.walletId, function(err) { - $log.debug('Backup stored'); - }); - }); - - $rootScope.$on('Local/DeviceError', function(event, err) { - self.showErrorPopup(err, function() { - if (isCordova && navigator && navigator.app) { - navigator.app.exitApp(); - } - }); - }); - - $rootScope.$on('Local/WalletImported', function(event, walletId) { - self.needsBackup = false; - storageService.setBackupFlag(walletId, function() { - $log.debug('Backup done stored'); - addressService.expireAddress(walletId, function(err) { - $timeout(function() { - self.txHistory = self.completeHistory = self.txHistorySearchResults = []; - storageService.removeTxHistory(walletId, function() { - self.startScan(walletId); - }); - }, 500); - }); - }); - }); - - $rootScope.$on('NewIncomingTx', function() { - self.newTx = true; - self.updateAll({ - walletStatus: null, - untilItChanges: true, - triggerTxUpdate: true, - }); - }); - - - $rootScope.$on('NewBlock', function() { - if (self.glideraEnabled) { - $timeout(function() { - self.updateGlidera(); - }); - } - if (self.coinbaseEnabled) { - $timeout(function() { - self.updateCoinbase(); - }); - } - if (self.pendingAmount) { - self.updateAll({ - walletStatus: null, - untilItChanges: null, - triggerTxUpdate: true, - }); - } else if (self.hasUnsafeConfirmed) { - $log.debug('Wallet has transactions with few confirmations. Updating.') - if (self.network == 'testnet') { - self.throttledUpdateHistory(); - } else { - self.debounceUpdateHistory(); - } - } - }); - - $rootScope.$on('BalanceUpdated', function(e, n) { - self.setBalance(n.data); - }); - - - //untilItChange TRUE - lodash.each(['NewOutgoingTx', 'NewOutgoingTxByThirdParty'], function(eventName) { - $rootScope.$on(eventName, function(event) { - self.newTx = true; - self.updateAll({ - walletStatus: null, - untilItChanges: true, - triggerTxUpdate: true, - }); - }); - }); - - //untilItChange FALSE - lodash.each(['NewTxProposal', 'TxProposalFinallyRejected', 'TxProposalRemoved', 'NewOutgoingTxByThirdParty', - 'Local/GlideraTx' - ], function(eventName) { - $rootScope.$on(eventName, function(event) { - self.updateAll({ - walletStatus: null, - untilItChanges: null, - triggerTxUpdate: true, - }); - }); - }); - - - //untilItChange Maybe - $rootScope.$on('Local/TxProposalAction', function(event, untilItChanges) { - self.newTx = untilItChanges; - self.updateAll({ - walletStatus: null, - untilItChanges: untilItChanges, - triggerTxUpdate: true, - }); - }); - - $rootScope.$on('ScanFinished', function() { - $log.debug('Scan Finished. Updating history'); - storageService.removeTxHistory(self.walletId, function() { - self.updateAll({ - walletStatus: null, - triggerTxUpdate: true, - }); - }); - }); - - lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy'], function(eventName) { - $rootScope.$on(eventName, function() { - var f = function() { - if (self.updating) { - return $timeout(f, 200); - }; - self.updatePendingTxps(); - }; - f(); - }); - }); - - $rootScope.$on('Local/NoWallets', function(event) { - $timeout(function() { - self.hasProfile = true; - self.noFocusedWallet = true; - self.isComplete = null; - self.walletName = null; - uxLanguage.update(); - }); - }); - - $rootScope.$on('Local/NewFocusedWallet', function() { - uxLanguage.update(); - self.setFocusedWallet(); - self.updateHistory(); - storageService.getCleanAndScanAddresses(function(err, walletId) { - - if (walletId && profileService.walletClients[walletId]) { - $log.debug('Clear last address cache and Scan ', walletId); - addressService.expireAddress(walletId, function(err) { - self.startScan(walletId); - }); - storageService.removeCleanAndScanAddresses(function() { - $rootScope.$emit('Local/NewFocusedWalletReady'); - }); - } else { - $rootScope.$emit('Local/NewFocusedWalletReady'); - } - }); - }); - - $rootScope.$on('Local/SetTab', function(event, tab, reset) { - self.setTab(tab, reset); - }); - - $rootScope.$on('disclaimerAccepted', function(event) { - $scope.isDisclaimerAccepted = true; - }); - - $rootScope.$on('Local/WindowResize', function() { - self.physicalScreenWidth = ((window.innerWidth > 0) ? window.innerWidth : screen.width); - }); - - $rootScope.$on('Local/NeedsConfirmation', function(event, txp, cb) { - - function openConfirmationPopup(txp, cb) { - - $scope.tx = txFormatService.processTx(txp); - - self.confirmationPopup = $ionicPopup.show({ - templateUrl: 'views/includes/confirm-tx.html', - scope: $scope, - }); - - $scope.processFee = function(amount, fee) { - var walletSettings = configService.getSync().wallet.settings; - var feeAlternativeIsoCode = walletSettings.alternativeIsoCode; - - $scope.feeLevel = feeService.feeOpts[feeService.getCurrentFeeLevel()]; - $scope.feeAlternativeStr = parseFloat((rateService.toFiat(fee, feeAlternativeIsoCode)).toFixed(2), 10) + ' ' + feeAlternativeIsoCode; - $scope.feeRateStr = (fee / (amount + fee) * 100).toFixed(2) + '%'; - }; - - $scope.cancel = function() { - return cb(); - }; - - $scope.accept = function() { - return cb(true); - }; - } - - openConfirmationPopup(txp, function(accept) { - self.confirmationPopup.close(); - return cb(accept); - }); - }); - - $rootScope.$on('Local/NeedsPassword', function(event, isSetup, cb) { - - function openPasswordPopup(isSetup, cb) { - $scope.data = {}; - $scope.data.password = null; - $scope.isSetup = isSetup; - $scope.isVerification = false; - $scope.loading = false; - var pass = null; - - self.passwordPopup = $ionicPopup.show({ - templateUrl: 'views/includes/password.html', - scope: $scope, - }); - - $scope.cancel = function() { - return cb('No spending password given'); - }; - - $scope.keyPress = function(event) { - if (!$scope.data.password || $scope.loading) return; - if (event.keyCode == 13) $scope.set(); - } - - $scope.set = function() { - $scope.loading = true; - $scope.error = null; - - $timeout(function() { - if (isSetup && !$scope.isVerification) { - $scope.loading = false; - $scope.isVerification = true; - pass = $scope.data.password; - $scope.data.password = null; - return; - } - if (isSetup && pass != $scope.data.password) { - $scope.loading = false; - $scope.error = gettext('Spending Passwords do not match'); - $scope.isVerification = false; - $scope.data.password = null; - pass = null; - return; - } - return cb(null, $scope.data.password); - }, 100); - }; - }; - - openPasswordPopup(isSetup, function(err, pass) { - self.passwordPopup.close(); - return cb(err, pass); - }); - - }); - - $rootScope.$on('Local/EmailUpdated', function(event, email) { - self.preferences.email = email; - }); - - lodash.each(['NewCopayer', 'CopayerUpdated'], function(eventName) { - $rootScope.$on(eventName, function() { - // Re try to open wallet (will triggers) - self.setFocusedWallet(); - }); - }); - - $rootScope.$on('Local/NewEncryptionSetting', function() { - var fc = profileService.focusedClient; - self.isPrivKeyEncrypted = fc.isPrivKeyEncrypted(); - $timeout(function() { - $rootScope.$apply(); - }); - }); - - - /* Start setup */ - lodash.assign(self, vanillaScope); - openURLService.init(); -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('joinController', - function($scope, $rootScope, $timeout, go, notification, profileService, configService, storageService, applicationService, gettext, lodash, ledger, trezor, platformInfo, derivationPathHelper, ongoingProcess) { - - var isChromeApp = platformInfo.isChromeApp; - var isDevel = platformInfo.isDevel; - - var self = this; - var defaults = configService.getDefaults(); - $scope.bwsurl = defaults.bws.url; - $scope.derivationPath = derivationPathHelper.default; - $scope.account = 1; - - this.onQrCodeScanned = function(data) { - $scope.secret = data; - $scope.joinForm.secret.$setViewValue(data); - $scope.joinForm.secret.$render(); - }; - - var updateSeedSourceSelect = function() { - self.seedOptions = [{ - id: 'new', - label: gettext('New Random Recovery Phrase'), - }, { - id: 'set', - label: gettext('Specify Recovery Phrase...'), - }]; - $scope.seedSource = self.seedOptions[0]; - - - if (isChromeApp) { - self.seedOptions.push({ - id: 'ledger', - label: 'Ledger Hardware Wallet', - }); - } - - if (isChromeApp || isDevel) { - self.seedOptions.push({ - id: 'trezor', - label: 'Trezor Hardware Wallet', - }); - } - }; - - this.setSeedSource = function() { - self.seedSourceId = $scope.seedSource.id; - - $timeout(function() { - $rootScope.$apply(); - }); - }; - - this.join = function(form) { - if (form && form.$invalid) { - self.error = gettext('Please enter the required fields'); - return; - } - - var opts = { - secret: form.secret.$modelValue, - myName: form.myName.$modelValue, - bwsurl: $scope.bwsurl, - } - - var setSeed = self.seedSourceId == 'set'; - if (setSeed) { - var words = form.privateKey.$modelValue; - if (words.indexOf(' ') == -1 && words.indexOf('prv') == 1 && words.length > 108) { - opts.extendedPrivateKey = words; - } else { - opts.mnemonic = words; - } - opts.passphrase = form.passphrase.$modelValue; - - var pathData = derivationPathHelper.parse($scope.derivationPath); - if (!pathData) { - this.error = gettext('Invalid derivation path'); - return; - } - opts.account = pathData.account; - opts.networkName = pathData.networkName; - opts.derivationStrategy = pathData.derivationStrategy; - } else { - opts.passphrase = form.createPassphrase.$modelValue; - } - - opts.walletPrivKey = $scope._walletPrivKey; // Only for testing - - - if (setSeed && !opts.mnemonic && !opts.extendedPrivateKey) { - - this.error = gettext('Please enter the wallet recovery phrase'); - return; - } - - if (self.seedSourceId == 'ledger' || self.seedSourceId == 'trezor') { - var account = $scope.account; - if (!account || account < 1) { - this.error = gettext('Invalid account number'); - return; - } - - if (self.seedSourceId == 'trezor') - account = account - 1; - - opts.account = account; - ongoingProcess.set('connecting' + self.seedSourceId, true); - var src = self.seedSourceId == 'ledger' ? ledger : trezor; - - src.getInfoForNewWallet(true, account, function(err, lopts) { - ongoingProcess.set('connecting' + self.seedSourceId, false); - if (err) { - self.error = err; - $scope.$apply(); - return; - } - opts = lodash.assign(lopts, opts); - self._join(opts); - }); - } else { - - self._join(opts); - } - }; - - this._join = function(opts) { - ongoingProcess.set('joiningWallet', true); - $timeout(function() { - profileService.joinWallet(opts, function(err) { - ongoingProcess.set('joiningWallet', false); - if (err) { - self.error = err; - $rootScope.$apply(); - return; - } - go.walletHome(); - }); - }, 100); - }; - - updateSeedSourceSelect(); - self.setSeedSource(); - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('addressbookController', function($rootScope, $scope, $timeout, lodash, profileService, addressService, addressbookService, bwcError) { - var self = $scope.self; - - var fc = profileService.focusedClient; - self.lockAddress = false; - self._address = null; - $scope.editAddressbook = false; - $scope.addAddressbookEntry = false; - $scope.selectedAddressbook = {}; - $scope.newAddress = address; - $scope.walletName = fc.credentials.walletName; - $scope.color = fc.backgroundColor; - $scope.addressbook = { - 'address': ($scope.newAddress || ''), - 'label': '' - }; - - $scope.checkClipboard = function() { - if (!$scope.newAddress) { - getClipboard(function(value) { - $scope.newAddress = value; - }); - } - }; - - $scope.beforeQrCodeScann = function() { - $scope.error = null; - $scope.addAddressbookEntry = true; - $scope.editAddressbook = false; - }; - - $scope.onQrCodeScanned = function(data, addressbookForm) { - $timeout(function() { - var form = addressbookForm; - if (data && form) { - data = data.replace('bitcoin:', ''); - form.address.$setViewValue(data); - form.address.$isValid = true; - form.address.$render(); - } - $scope.$digest(); - }, 100); - }; - - $scope.toggleEditAddressbook = function() { - $scope.editAddressbook = !$scope.editAddressbook; - $scope.selectedAddressbook = {}; - $scope.addAddressbookEntry = false; - }; - - $scope.selectAddressbook = function(addr) { - self.setForm(addr); - $scope.cancel(); - }; - - $scope.toggleSelectAddressbook = function(addr) { - $scope.selectedAddressbook[addr] = $scope.selectedAddressbook[addr] ? false : true; - }; - - $scope.toggleAddAddressbookEntry = function() { - $scope.error = null; - $scope.addressbook = { - 'address': '', - 'label': '' - }; - $scope.addAddressbookEntry = !$scope.addAddressbookEntry; - }; - - $scope.contactList = function() { - $scope.error = null; - addressbookService.list(function(err, ab) { - if (err) { - $scope.error = err; - return; - } - $scope.list = ab; - $scope.isEmptyList = lodash.isEmpty($scope.list); - $timeout(function() { - $scope.$digest(); - }); - }); - }; - - $scope.setSelectedWalletsOpt = function(val) { - $scope.selectedWalletsOpt = val; - }; - - $scope.add = function(addressbook) { - $scope.error = null; - $timeout(function() { - addressbookService.add(addressbook, function(err, ab) { - if (err) { - $scope.error = err; - return; - } - $rootScope.$emit('Local/AddressbookUpdated', ab); - $scope.list = ab; - $scope.isEmptyList = lodash.isEmpty($scope.list); - $scope.editAddressbook = true; - $scope.toggleEditAddressbook(); - $scope.$digest(); - }); - }, 100); - }; - - $scope.remove = function(addr) { - $scope.error = null; - $timeout(function() { - addressbookService.remove(addr, function(err, ab) { - if (err) { - $scope.error = err; - return; - } - $rootScope.$emit('Local/AddressbookUpdated', ab); - $scope.list = ab; - $scope.isEmptyList = lodash.isEmpty($scope.list); - if ($scope.isEmptyList) - $scope.editAddressbook = false; - $scope.$digest(); - }); - }, 100); - }; - - $scope.selectWallet = function(walletId, walletName) { - var client = profileService.getClient(walletId); - $scope.errorSelectedWallet = {}; - - profileService.isReady(client, function(err) { - if (err) $scope.errorSelectedWallet[walletId] = bwcError.msg(err); - else { - $scope.gettingAddress = true; - $scope.selectedWalletName = walletName; - $timeout(function() { - $scope.$apply(); - }); - - addressService.getAddress(walletId, false, function(err, addr) { - $scope.gettingAddress = false; - if (err) { - self.error = err; - $scope.cancelAddress(); - return; - } - - self.setForm(addr); - $scope.cancel(); - }); - } - }); - }; - - $scope.cancelAddress = function() { - self.resetForm(); - $scope.cancel(); - }; - - $scope.cancel = function() { - $scope.addressbookModal.hide(); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('coinbaseConfirmationController', function($scope, $timeout, coinbaseService, applicationService) { - - $scope.ok = function() { - - coinbaseService.logout($scope.network, function() { - - $timeout(function() { - applicationService.restart(); - }, 1000); - }); - $scope.cancel(); - }; - - $scope.cancel = function() { - $scope.coinbaseConfirmationModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('coinbaseTxDetailsController', function($scope, $rootScope, coinbaseService) { - - $scope.remove = function() { - coinbaseService.savePendingTransaction($scope.tx, { - remove: true - }, function(err) { - $rootScope.$emit('Local/CoinbaseTx'); - $scope.cancel(); - }); - }; - - $scope.cancel = function() { - $scope.coinbaseTxDetailsModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('confirmationController', function($scope) { - - $scope.ok = function() { - $scope.loading = true; - $scope.okAction(); - $scope.confirmationModal.hide(); - }; - - $scope.cancel = function() { - $scope.confirmationModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('customAmountController', function($scope, $timeout, $filter, platformInfo, rateService) { - var self = $scope.self; - - $scope.unitName = self.unitName; - $scope.alternativeAmount = self.alternativeAmount; - $scope.alternativeName = self.alternativeName; - $scope.alternativeIsoCode = self.alternativeIsoCode; - $scope.isRateAvailable = self.isRateAvailable; - $scope.unitToSatoshi = self.unitToSatoshi; - $scope.unitDecimals = self.unitDecimals; - var satToUnit = 1 / self.unitToSatoshi; - $scope.showAlternative = false; - $scope.isCordova = platformInfo.isCordova; - - Object.defineProperty($scope, - "_customAlternative", { - get: function() { - return $scope.customAlternative; - }, - set: function(newValue) { - $scope.customAlternative = newValue; - if (typeof(newValue) === 'number' && $scope.isRateAvailable) { - $scope.customAmount = parseFloat((rateService.fromFiat(newValue, $scope.alternativeIsoCode) * satToUnit).toFixed($scope.unitDecimals), 10); - } else { - $scope.customAmount = null; - } - }, - enumerable: true, - configurable: true - }); - - Object.defineProperty($scope, - "_customAmount", { - get: function() { - return $scope.customAmount; - }, - set: function(newValue) { - $scope.customAmount = newValue; - if (typeof(newValue) === 'number' && $scope.isRateAvailable) { - $scope.customAlternative = parseFloat((rateService.toFiat(newValue * $scope.unitToSatoshi, $scope.alternativeIsoCode)).toFixed(2), 10); - } else { - $scope.customAlternative = null; - } - $scope.alternativeAmount = $scope.customAlternative; - }, - enumerable: true, - configurable: true - }); - - $scope.submitForm = function(form) { - var satToBtc = 1 / 100000000; - var amount = form.amount.$modelValue; - var amountSat = parseInt((amount * $scope.unitToSatoshi).toFixed(0)); - $timeout(function() { - $scope.customizedAmountUnit = amount + ' ' + $scope.unitName; - $scope.customizedAlternativeUnit = $filter('formatFiatAmount')(form.alternative.$modelValue) + ' ' + $scope.alternativeIsoCode; - if ($scope.unitName == 'bits') { - amount = (amountSat * satToBtc).toFixed(8); - } - $scope.customizedAmountBtc = amount; - }, 1); - }; - - $scope.toggleAlternative = function() { - $scope.showAlternative = !$scope.showAlternative; - }; - - $scope.shareAddress = function(uri) { - if (platformInfo.isCordova) { - window.plugins.socialsharing.share(uri, null, null, null); - } - }; - - $scope.cancel = function() { - $scope.customAmountModal.hide(); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('glideraConfirmationController', function($scope, $timeout, storageService, applicationService) { - - $scope.ok = function() { - storageService.removeGlideraToken($scope.network, function() { - $timeout(function() { - applicationService.restart(); - }, 100); - }); - $scope.cancel(); - }; - - $scope.cancel = function() { - $scope.glideraConfirmationModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('glideraTxDetailsController', function($scope) { - - $scope.cancel = function() { - $scope.glideraTxDetailsModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('payproController', function($scope) { - var self = $scope.self; - - $scope.alternative = self.alternativeAmount; - $scope.alternativeIsoCode = self.alternativeIsoCode; - $scope.isRateAvailable = self.isRateAvailable; - $scope.unitTotal = ($scope.paypro.amount * self.satToUnit).toFixed(self.unitDecimals); - $scope.unitName = self.unitName; - - $scope.cancel = function() { - $scope.payproModal.hide(); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('scannerController', function($scope, $timeout) { - - // QR code Scanner - var video; - var canvas; - var $video; - var context; - var localMediaStream; - var prevResult; - var scanTimer; - - var _scan = function(evt) { - if (localMediaStream) { - context.drawImage(video, 0, 0, 300, 225); - try { - qrcode.decode(); - } catch (e) { - //qrcodeError(e); - } - } - scanTimer = $timeout(_scan, 800); - }; - - var _scanStop = function() { - $timeout.cancel(scanTimer); - if (localMediaStream && localMediaStream.active) { - var localMediaStreamTrack = localMediaStream.getTracks(); - for (var i = 0; i < localMediaStreamTrack.length; i++) { - localMediaStreamTrack[i].stop(); - } - } else { - try { - localMediaStream.stop(); - } catch (e) { - // Older Chromium not support the STOP function - }; - } - localMediaStream = null; - video.src = ''; - }; - - qrcode.callback = function(data) { - if (prevResult != data) { - prevResult = data; - return; - } - _scanStop(); - $scope.cancel(); - $scope.onScan({ - data: data - }); - }; - - var _successCallback = function(stream) { - video.src = (window.URL && window.URL.createObjectURL(stream)) || stream; - localMediaStream = stream; - video.play(); - $timeout(_scan, 1000); - }; - - var _videoError = function(err) { - $scope.cancel(); - }; - - var setScanner = function() { - navigator.getUserMedia = navigator.getUserMedia || - navigator.webkitGetUserMedia || navigator.mozGetUserMedia || - navigator.msGetUserMedia; - window.URL = window.URL || window.webkitURL || - window.mozURL || window.msURL; - }; - - $scope.init = function() { - setScanner(); - $timeout(function() { - if ($scope.beforeScan) { - $scope.beforeScan(); - } - canvas = document.getElementById('qr-canvas'); - context = canvas.getContext('2d'); - - video = document.getElementById('qrcode-scanner-video'); - $video = angular.element(video); - canvas.width = 300; - canvas.height = 225; - context.clearRect(0, 0, 300, 225); - - navigator.getUserMedia({ - video: true - }, _successCallback, _videoError); - }, 500); - }; - - $scope.cancel = function() { - _scanStop(); - $scope.scannerModal.hide(); - $scope.scannerModal.remove(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('searchController', function($scope) { - var self = $scope.self; - $scope.search = ''; - - $scope.cancel = function() { - $scope.searchModal.hide(); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('txDetailsController', function($rootScope, $log, $scope, $filter, $ionicPopup, gettextCatalog, profileService, configService, lodash) { - - var self = $scope.self; - var fc = profileService.focusedClient; - var config = configService.getSync(); - var configWallet = config.wallet; - var walletSettings = configWallet.settings; - - $scope.alternativeIsoCode = walletSettings.alternativeIsoCode; - $scope.color = fc.backgroundColor; - $scope.copayerId = fc.credentials.copayerId; - $scope.isShared = fc.credentials.n > 1; - - $scope.btx.amountStr = profileService.formatAmount($scope.btx.amount, true) + ' ' + walletSettings.unitName; - $scope.btx.feeStr = profileService.formatAmount($scope.btx.fees, true) + ' ' + walletSettings.unitName; - - $scope.showCommentPopup = function() { - $scope.data = { - comment: $scope.btx.note ? $scope.btx.note.body : '', - }; - - var commentPopup = $ionicPopup.show({ - templateUrl: "views/includes/note.html", - scope: $scope, - }); - - $scope.commentPopupClose = function() { - commentPopup.close(); - }; - - $scope.commentPopupSave = function() { - $log.debug('Saving note'); - var args = { - txid: $scope.btx.txid, - }; - - if (!lodash.isEmpty($scope.data.comment)) { - args.body = $scope.data.comment; - }; - - fc.editTxNote(args, function(err) { - if (err) { - $log.debug('Could not save tx comment'); - return; - } - // This is only to refresh the current screen data - $scope.btx.note = null; - if (args.body) { - $scope.btx.note = {}; - $scope.btx.note.body = $scope.data.comment; - $scope.btx.note.editedByName = fc.credentials.copayerName; - $scope.btx.note.editedOn = Math.floor(Date.now() / 1000); - } - $scope.btx.searcheableString = null; - commentPopup.close(); - }); - }; - }; - - $scope.getAlternativeAmount = function() { - var satToBtc = 1 / 100000000; - - fc.getFiatRate({ - code: $scope.alternativeIsoCode, - ts: $scope.btx.time * 1000 - }, function(err, res) { - if (err) { - $log.debug('Could not get historic rate'); - return; - } - if (res && res.rate) { - var alternativeAmountBtc = ($scope.btx.amount * satToBtc).toFixed(8); - $scope.rateDate = res.fetchedOn; - $scope.rateStr = res.rate + ' ' + $scope.alternativeIsoCode; - $scope.alternativeAmountStr = $filter('formatFiatAmount')(alternativeAmountBtc * res.rate) + ' ' + $scope.alternativeIsoCode; - $scope.$apply(); - } - }); - }; - - $scope.getShortNetworkName = function() { - var n = fc.credentials.network; - return n.substring(0, 4); - }; - - $scope.copyToClipboard = function(addr) { - if (!addr) return; - self.copyToClipboard(addr); - }; - - $scope.cancel = function() { - $scope.txDetailsModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('txStatusController', function($scope, $timeout) { - - if ($scope.cb) $timeout($scope.cb, 100); - - $scope.cancel = function() { - $scope.txStatusModal.hide(); - }; - -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('txpDetailsController', function($scope, $rootScope, $timeout, $interval, $ionicModal, platformInfo, txStatus, $ionicScrollDelegate, txFormatService, fingerprintService, bwcError, gettextCatalog, lodash, profileService, walletService) { - var self = $scope.self; - var tx = $scope.tx; - var copayers = $scope.copayers; - var isGlidera = $scope.isGlidera; - var now = Math.floor(Date.now() / 1000); - var fc = profileService.focusedClient; - $scope.loading = null; - $scope.copayerId = fc.credentials.copayerId; - $scope.isShared = fc.credentials.n > 1; - $scope.canSign = fc.canSign() || fc.isPrivKeyExternal(); - $scope.color = fc.backgroundColor; - - checkPaypro(); - - // ToDo: use tx.customData instead of tx.message - if (tx.message === 'Glidera transaction' && isGlidera) { - tx.isGlidera = true; - if (tx.canBeRemoved) { - tx.canBeRemoved = (Date.now() / 1000 - (tx.ts || tx.createdOn)) > GLIDERA_LOCK_TIME; - } - } - - $scope.sign = function(txp) { - $scope.error = null; - $scope.loading = 'Signing Transaction'; - - fingerprintService.check(fc, function(err) { - if (err) { - $scope.error = bwcError.msg(err); - $scope.loading = null; - return; - } - - handleEncryptedWallet(function(err) { - if (err) { - $scope.error = bwcError.msg(err); - $scope.loading = null; - return; - } - - walletService.signTx(fc, txp, function(err, signedTxp) { - walletService.lock(fc); - if (err) { - $scope.error = bwcError.msg(err); - $scope.loading = null; - return; - } - - if (signedTxp.status == 'accepted') { - $scope.loading = 'Broadcasting Transaction'; - walletService.broadcastTx(fc, signedTxp, function(err, broadcastedTxp) { - $scope.loading = null; - $scope.$emit('UpdateTx'); - $scope.close(broadcastedTxp); - if (err) { - $scope.error = err; - } - }); - } else { - $scope.loading = null; - $scope.$emit('UpdateTx'); - $scope.close(signedTxp); - } - }); - }); - }); - }; - - $scope.reject = function(txp) { - $scope.loading = 'Rejecting payment'; - $scope.error = null; - - $timeout(function() { - walletService.rejectTx(fc, txp, function(err, txpr) { - $scope.loading = null; - - if (err) { - $scope.$emit('UpdateTx'); - $scope.error = bwcError.msg(err, gettextCatalog.getString('Could not reject payment')); - $scope.$digest(); - } else { - $scope.close(txpr); - } - }); - }, 10); - }; - - $scope.remove = function(txp) { - $scope.loading = 'Deleting Payment'; - $scope.error = null; - - $timeout(function() { - walletService.removeTx(fc, txp, function(err) { - $scope.loading = null; - - // Hacky: request tries to parse an empty response - if (err && !(err.message && err.message.match(/Unexpected/))) { - $scope.$emit('UpdateTx'); - $scope.error = bwcError.msg(err, gettextCatalog.getString('Could not delete payment proposal')); - $scope.$digest(); - return; - } - $scope.close(); - }); - }, 10); - }; - - $scope.broadcast = function(txp) { - $scope.loading = 'Broadcasting Payment'; - $scope.error = null; - - $timeout(function() { - walletService.broadcastTx(fc, txp, function(err, txpb) { - $scope.loading = null; - - if (err) { - $scope.error = bwcError.msg(err, gettextCatalog.getString('Could not broadcast payment')); - $scope.$digest(); - return; - } - $scope.close(txpb); - }); - }, 10); - }; - - $scope.getShortNetworkName = function() { - return fc.credentials.networkName.substring(0, 4); - }; - - function checkPaypro() { - if (tx.payProUrl && !platformInfo.isChromeApp) { - fc.fetchPayPro({ - payProUrl: tx.payProUrl, - }, function(err, paypro) { - if (err) return; - tx.paypro = paypro; - paymentTimeControl(tx.paypro.expires); - $timeout(function() { - $ionicScrollDelegate.resize(); - }, 100); - }); - } - }; - - function paymentTimeControl(expirationTime) { - $scope.paymentExpired = false; - setExpirationTime(); - - self.countDown = $interval(function() { - setExpirationTime(); - }, 1000); - - function setExpirationTime() { - var now = Math.floor(Date.now() / 1000); - if (now > expirationTime) { - $scope.paymentExpired = true; - if (self.countDown) $interval.cancel(self.countDown); - return; - } - var totalSecs = expirationTime - now; - var m = Math.floor(totalSecs / 60); - var s = totalSecs % 60; - $scope.expires = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2); - }; - }; - - lodash.each(['TxProposalRejectedBy', 'TxProposalAcceptedBy', 'transactionProposalRemoved', 'TxProposalRemoved', 'NewOutgoingTx', 'UpdateTx'], function(eventName) { - $rootScope.$on(eventName, function() { - fc.getTx($scope.tx.id, function(err, tx) { - if (err) { - if (err.message && err.message == 'TX_NOT_FOUND' && - (eventName == 'transactionProposalRemoved' || eventName == 'TxProposalRemoved')) { - $scope.tx.removed = true; - $scope.tx.canBeRemoved = false; - $scope.tx.pendingForUs = false; - $scope.$apply(); - return; - } - return; - } - - var action = lodash.find(tx.actions, { - copayerId: fc.credentials.copayerId - }); - - $scope.tx = txFormatService.processTx(tx); - - if (!action && tx.status == 'pending') - $scope.tx.pendingForUs = true; - - $scope.updateCopayerList(); - $scope.$apply(); - }); - }); - }); - - $scope.updateCopayerList = function() { - lodash.map($scope.copayers, function(cp) { - lodash.each($scope.tx.actions, function(ac) { - if (cp.id == ac.copayerId) { - cp.action = ac.type; - } - }); - }); - }; - - function handleEncryptedWallet(cb) { - if (!walletService.isEncrypted(fc)) return cb(); - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(fc, password)); - }); - }; - - $scope.copyToClipboard = function(addr) { - if (!addr) return; - self.copyToClipboard(addr); - }; - - $scope.close = function(txp) { - $scope.loading = null; - if (txp) { - var type = txStatus.notify(txp); - $scope.openStatusModal(type, txp, function() { - $scope.$emit('Local/TxProposalAction', txp.status == 'broadcasted'); - }); - } else { - $timeout(function() { - $scope.$emit('Local/TxProposalAction'); - }, 100); - } - $scope.cancel(); - }; - - $scope.openStatusModal = function(type, txp, cb) { - $scope.type = type; - $scope.tx = txFormatService.processTx(txp); - $scope.cb = cb; - - $ionicModal.fromTemplateUrl('views/modals/tx-status.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.txStatusModal = modal; - $scope.txStatusModal.show(); - }); - }; - - $scope.cancel = function() { - $scope.txpDetailsModal.hide(); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('walletsController', function($scope, bwcError, profileService) { - - $scope.selectWallet = function(walletId) { - - var client = profileService.getClient(walletId); - $scope.errorSelectedWallet = {}; - - profileService.isReady(client, function(err) { - if (err) { - $scope.errorSelectedWallet[walletId] = bwcError.msg(err); - return; - } - - $scope.$emit('walletSelected', walletId); - }); - }; - - $scope.cancel = function() { - $scope.walletsModal.hide(); - }; - -}); - -angular.module('copayApp.controllers').controller('paperWalletController', - function($scope, $timeout, $log, $ionicModal, configService, profileService, go, addressService, txStatus, bitcore, ongoingProcess) { - - var fc = profileService.focusedClient; - var rawTx; - - $scope.onQrCodeScanned = function(data) { - $scope.inputData = data; - $scope.onData(data); - }; - - $scope.onData = function(data) { - $scope.error = null; - $scope.scannedKey = data; - $scope.isPkEncrypted = (data.substring(0, 2) == '6P'); - }; - - function _scanFunds(cb) { - function getPrivateKey(scannedKey, isPkEncrypted, passphrase, cb) { - if (!isPkEncrypted) return cb(null, scannedKey); - fc.decryptBIP38PrivateKey(scannedKey, passphrase, null, cb); - }; - - function getBalance(privateKey, cb) { - fc.getBalanceFromPrivateKey(privateKey, cb); - }; - - function checkPrivateKey(privateKey) { - try { - new bitcore.PrivateKey(privateKey, 'livenet'); - } catch (err) { - return false; - } - return true; - }; - - getPrivateKey($scope.scannedKey, $scope.isPkEncrypted, $scope.passphrase, function(err, privateKey) { - if (err) return cb(err); - if (!checkPrivateKey(privateKey)) return cb(new Error('Invalid private key')); - - getBalance(privateKey, function(err, balance) { - if (err) return cb(err); - return cb(null, privateKey, balance); - }); - }); - }; - - $scope.scanFunds = function() { - $scope.privateKey = ''; - $scope.balanceSat = 0; - $scope.error = null; - - ongoingProcess.set('scanning', true); - $timeout(function() { - _scanFunds(function(err, privateKey, balance) { - ongoingProcess.set('scanning', false); - if (err) { - $log.error(err); - $scope.error = err.message || err.toString(); - } else { - $scope.privateKey = privateKey; - $scope.balanceSat = balance; - var config = configService.getSync().wallet.settings; - $scope.balance = profileService.formatAmount(balance) + ' ' + config.unitName; - } - - $scope.$apply(); - }); - }, 100); - }; - - function _sweepWallet(cb) { - addressService.getAddress(fc.credentials.walletId, true, function(err, destinationAddress) { - if (err) return cb(err); - - fc.buildTxFromPrivateKey($scope.privateKey, destinationAddress, null, function(err, tx) { - if (err) return cb(err); - - fc.broadcastRawTx({ - rawTx: tx.serialize(), - network: 'livenet' - }, function(err, txid) { - if (err) return cb(err); - return cb(null, destinationAddress, txid); - }); - }); - }); - }; - - $scope.sweepWallet = function() { - ongoingProcess.set('sweepingWallet', true); - $scope.sending = true; - $scope.error = null; - - $timeout(function() { - _sweepWallet(function(err, destinationAddress, txid) { - ongoingProcess.set('sweepingWallet', false); - - if (err) { - $scope.error = err.message || err.toString(); - $log.error(err); - } else { - var type = txStatus.notify(txp); - $scope.openStatusModal(type, txp, function() { - go.walletHome(); - }); - } - $scope.$apply(); - }); - }, 100); - }; - - $scope.openStatusModal = function(type, txp, cb) { - $scope.type = type; - $scope.tx = txFormatService.processTx(txp); - $scope.color = fc.backgroundColor; - $scope.cb = cb; - - $ionicModal.fromTemplateUrl('views/modals/tx-status.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.txStatusModal = modal; - $scope.txStatusModal.show(); - }); - }; - - }); - -'use strict'; -angular.module('copayApp.controllers').controller('paymentUriController', - function($rootScope, $scope, $stateParams, $location, $timeout, profileService, configService, lodash, bitcore, go) { - function strip(number) { - return (parseFloat(number.toPrecision(12))); - }; - - // Build bitcoinURI with querystring - this.init = function() { - var query = []; - this.bitcoinURI = $stateParams.url; - - var URI = bitcore.URI; - var isUriValid = URI.isValid(this.bitcoinURI); - if (!URI.isValid(this.bitcoinURI)) { - this.error = true; - return; - } - var uri = new URI(this.bitcoinURI); - - if (uri && uri.address) { - var config = configService.getSync().wallet.settings; - var unitToSatoshi = config.unitToSatoshi; - var satToUnit = 1 / unitToSatoshi; - var unitName = config.unitName; - - if (uri.amount) { - uri.amount = strip(uri.amount * satToUnit) + ' ' + unitName; - } - uri.network = uri.address.network.name; - this.uri = uri; - } - }; - - this.getWallets = function(network) { - - $scope.wallets = []; - lodash.forEach(profileService.getWallets(network), function(w) { - var client = profileService.getClient(w.id); - profileService.isReady(client, function(err) { - if (err) return; - $scope.wallets.push(w); - }) - }); - }; - - this.selectWallet = function(wid) { - var self = this; - profileService.setAndStoreFocus(wid, function() {}); - go.walletHome(); - $timeout(function() { - $rootScope.$emit('paymentUri', self.bitcoinURI); - }, 1000); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesController', - function($scope, $rootScope, $timeout, $log, configService, profileService, fingerprintService, walletService) { - - var fc; - var config = configService.getSync(); - - var disableFocusListener = $rootScope.$on('Local/NewFocusedWalletReady', function() { - $scope.init(); - }); - - $scope.$on('$destroy', function() { - disableFocusListener(); - }); - - $scope.init = function() { - $scope.externalSource = null; - - fc = profileService.focusedClient; - if (fc) { - $scope.encryptEnabled = walletService.isEncrypted(fc); - if (fc.isPrivKeyExternal) - $scope.externalSource = fc.getPrivKeyExternalSourceName() == 'ledger' ? 'Ledger' : 'Trezor'; - - // TODO externalAccount - //this.externalIndex = fc.getExternalIndex(); - } - - $scope.touchidAvailable = fingerprintService.isAvailable(); - $scope.touchidEnabled = config.touchIdFor ? config.touchIdFor[fc.credentials.walletId] : null; - - $scope.deleted = false; - if (fc.credentials && !fc.credentials.mnemonicEncrypted && !fc.credentials.mnemonic) { - $scope.deleted = true; - } - }; - - var handleEncryptedWallet = function(cb) { - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(fc, password)); - }); - }; - - $scope.encryptChange = function() { - if (!fc) return; - var val = $scope.encryptEnabled; - - var setPrivateKeyEncryption = function(password, cb) { - $log.debug('Encrypting private key for', fc.credentials.walletName); - - fc.setPrivateKeyEncryption(password); - fc.lock(); - profileService.updateCredentials(JSON.parse(fc.export()), function() { - $log.debug('Wallet encrypted'); - return cb(); - }); - }; - - var disablePrivateKeyEncryption = function(cb) { - $log.debug('Disabling private key encryption for', fc.credentials.walletName); - - try { - fc.disablePrivateKeyEncryption(); - } catch (e) { - return cb(e); - } - profileService.updateCredentials(JSON.parse(fc.export()), function() { - $log.debug('Wallet encryption disabled'); - return cb(); - }); - }; - - if (val && !walletService.isEncrypted(fc)) { - $rootScope.$emit('Local/NeedsPassword', true, function(err, password) { - if (err || !password) { - $scope.encryptEnabled = false; - return; - } - setPrivateKeyEncryption(password, function() { - $rootScope.$emit('Local/NewEncryptionSetting'); - $scope.encryptEnabled = true; - }); - }); - } else { - if (!val && walletService.isEncrypted(fc)) { - handleEncryptedWallet(function(err) { - if (err) { - $scope.encryptEnabled = true; - return; - } - disablePrivateKeyEncryption(function(err) { - $rootScope.$emit('Local/NewEncryptionSetting'); - if (err) { - $scope.encryptEnabled = true; - $log.error(err); - return; - } - $scope.encryptEnabled = false; - }); - }); - } - } - }; - - $scope.touchidChange = function() { - var walletId = fc.credentials.walletId; - - var opts = { - touchIdFor: {} - }; - opts.touchIdFor[walletId] = $scope.touchidEnabled; - - fingerprintService.check(fc, function(err) { - if (err) { - $log.debug(err); - $timeout(function() { - $scope.touchidError = true; - $scope.touchidEnabled = true; - }, 100); - return; - } - configService.set(opts, function(err) { - if (err) { - $log.debug(err); - $scope.touchidError = true; - $scope.touchidEnabled = false; - } - }); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesAbout', - function() {}); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesAliasController', - function($scope, $timeout, configService, profileService, go) { - var fc = profileService.focusedClient; - var walletId = fc.credentials.walletId; - var config = configService.getSync(); - - config.aliasFor = config.aliasFor || {}; - $scope.alias = config.aliasFor[walletId] || fc.credentials.walletName; - - $scope.save = function() { - var opts = { - aliasFor: {} - }; - opts.aliasFor[walletId] = $scope.alias; - - configService.set(opts, function(err) { - if (err) { - $scope.$emit('Local/DeviceError', err); - return; - } - $scope.$emit('Local/AliasUpdated'); - $timeout(function() { - go.path('preferences'); - }, 50); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesAltCurrencyController', - function($scope, $log, $timeout, configService, rateService, lodash, go, profileService, walletService) { - - var config = configService.getSync(); - var next = 10; - var completeAlternativeList; - $scope.currentCurrency = config.wallet.settings.alternativeIsoCode; - $scope.listComplete = false; - - $scope.init = function() { - rateService.whenAvailable(function() { - completeAlternativeList = rateService.listAlternatives(); - lodash.remove(completeAlternativeList, function(c) { - return c.isoCode == 'BTC'; - }); - $scope.altCurrencyList = completeAlternativeList.slice(0, next); - }); - }; - - $scope.loadMore = function() { - $timeout(function() { - $scope.altCurrencyList = completeAlternativeList.slice(0, next); - next += 10; - $scope.listComplete = $scope.altCurrencyList.length >= completeAlternativeList.length; - $scope.$broadcast('scroll.infiniteScrollComplete'); - }, 100); - }; - - $scope.save = function(newAltCurrency) { - var opts = { - wallet: { - settings: { - alternativeName: newAltCurrency.name, - alternativeIsoCode: newAltCurrency.isoCode, - } - } - }; - - configService.set(opts, function(err) { - if (err) $log.warn(err); - go.preferencesGlobal(); - $scope.$emit('Local/UnitSettingUpdated'); - walletService.updateRemotePreferences(profileService.getClients(), {}, function() { - $log.debug('Remote preferences saved'); - }); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesBwsUrlController', - function($scope, $log, configService, applicationService, profileService, storageService) { - $scope.error = null; - $scope.success = null; - - var fc = profileService.focusedClient; - var walletId = fc.credentials.walletId; - var defaults = configService.getDefaults(); - var config = configService.getSync(); - - $scope.bwsurl = (config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url; - - $scope.resetDefaultUrl = function() { - $scope.bwsurl = defaults.bws.url; - }; - - $scope.save = function() { - - var bws; - switch ($scope.bwsurl) { - case 'prod': - case 'production': - bws = 'https://bws.bitpay.com/bws/api' - break; - case 'sta': - case 'staging': - bws = 'https://bws-staging.b-pay.net/bws/api' - break; - case 'loc': - case 'local': - bws = 'http://localhost:3232/bws/api' - break; - }; - if (bws) { - $log.info('Using BWS URL Alias to ' + bws); - $scope.bwsurl = bws; - } - - var opts = { - bwsFor: {} - }; - opts.bwsFor[walletId] = $scope.bwsurl; - - configService.set(opts, function(err) { - if (err) $log.debug(err); - storageService.setCleanAndScanAddresses(walletId, function() { - applicationService.restart(); - }); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesCoinbaseController', - function($scope, $timeout, $ionicModal, applicationService, coinbaseService) { - - this.revokeToken = function(testnet) { - $scope.network = testnet ? 'testnet' : 'livenet'; - - $ionicModal.fromTemplateUrl('views/modals/coinbase-confirmation.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.coinbaseConfirmationModal = modal; - $scope.coinbaseConfirmationModal.show(); - }); - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesColorController', function($scope, $log, configService, profileService, go) { - - $scope.colorList = [ - '#DD4B39', - '#F38F12', - '#FAA77F', - '#D0B136', - '#9EDD72', - '#29BB9C', - '#019477', - '#77DADA', - '#4A90E2', - '#484ED3', - '#9B59B6', - '#E856EF', - '#FF599E', - '#7A8C9E', - ]; - - var fc = profileService.focusedClient; - var walletId = fc.credentials.walletId; - var config = configService.getSync(); - config.colorFor = config.colorFor || {}; - - $scope.currentColor = config.colorFor[walletId] || '#4A90E2'; - - $scope.save = function(color) { - var opts = { - colorFor: {} - }; - opts.colorFor[walletId] = color; - - configService.set(opts, function(err) { - go.preferences(); - if (err) $log.warn(err); - $scope.$emit('Local/ColorUpdated'); - }); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesDeleteWalletController', - function($scope, $rootScope, $filter, $timeout, $log, $ionicModal, storageService, notification, profileService, platformInfo, go, gettext, gettextCatalog, applicationService, ongoingProcess) { - var isCordova = platformInfo.isCordova; - $scope.isCordova = isCordova; - $scope.error = null; - - var delete_msg = gettextCatalog.getString('Are you sure you want to delete this wallet?'); - var accept_msg = gettextCatalog.getString('Accept'); - var cancel_msg = gettextCatalog.getString('Cancel'); - var confirm_msg = gettextCatalog.getString('Confirm'); - - var _modalDeleteWallet = function() { - $scope.title = delete_msg; - $scope.accept_msg = accept_msg; - $scope.cancel_msg = cancel_msg; - $scope.confirm_msg = confirm_msg; - $scope.okAction = doDeleteWallet; - $scope.loading = false; - - $ionicModal.fromTemplateUrl('views/modals/confirmation.html', { - scope: $scope - }).then(function(modal) { - $scope.confirmationModal = modal; - $scope.confirmationModal.show(); - }); - }; - - var doDeleteWallet = function() { - ongoingProcess.set('deletingWallet', true); - var fc = profileService.focusedClient; - var name = fc.credentials.walletName; - var walletName = (fc.alias || '') + ' [' + name + ']'; - - profileService.deleteWalletClient(fc, function(err) { - ongoingProcess.set('deletingWallet', false); - if (err) { - $scope.error = err.message || err; - } else { - go.walletHome(); - notification.success(gettextCatalog.getString('Success'), gettextCatalog.getString('The wallet "{{walletName}}" was deleted', { - walletName: walletName - })); - } - }); - }; - - $scope.deleteWallet = function() { - if (isCordova) { - navigator.notification.confirm( - delete_msg, - function(buttonIndex) { - if (buttonIndex == 1) { - doDeleteWallet(); - } - }, - confirm_msg, [accept_msg, cancel_msg] - ); - } else { - _modalDeleteWallet(); - } - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesDeleteWordsController', function($scope, confirmDialog, lodash, notification, profileService, go, gettext) { - var fc = profileService.focusedClient; - var msg = gettext('Are you sure you want to delete the recovery phrase?'); - var successMsg = gettext('Recovery phrase deleted'); - - if (lodash.isEmpty(fc.credentials.mnemonic) && lodash.isEmpty(fc.credentials.mnemonicEncrypted)) - $scope.deleted = true; - - $scope.delete = function() { - confirmDialog.show(msg, function(ok) { - if (ok) { - fc.clearMnemonic(); - profileService.updateCredentials(JSON.parse(fc.export()), function() { - notification.success(successMsg); - go.walletHome(); - }); - } - }); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesEmailController', function($rootScope, $scope, go, profileService, walletService) { - $scope.save = function(form) { - $scope.error = null; - $scope.saving = true; - var fc = profileService.focusedClient; - var email = $scope.email || ''; - - walletService.updateRemotePreferences(fc, { - email: email, - }, function(err) { - $scope.saving = false; - if (!err) - $rootScope.$emit('Local/EmailUpdated', email); - go.path('preferences'); - }); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesFeeController', function($scope, $timeout, configService, feeService) { - - $scope.loading = true; - feeService.getFeeLevels(function(levels) { - $scope.loading = false; - $scope.feeOpts = feeService.feeOpts; - $scope.currentFeeLevel = feeService.getCurrentFeeLevel(); - $scope.feeLevels = levels; - $scope.$apply(); - }); - - $scope.save = function(newFee) { - var opts = { - wallet: { - settings: { - feeLevel: newFee.level - } - } - }; - - configService.set(opts, function(err) { - if (err) $log.debug(err); - $scope.currentFeeLevel = newFee.level; - $timeout(function() { - $scope.$apply(); - }, 10); - }); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesGlideraController', - function($scope, $timeout, $ionicModal, profileService, applicationService, glideraService, storageService) { - - this.getEmail = function(token) { - var self = this; - glideraService.getEmail(token, function(error, data) { - self.email = data; - }); - }; - - this.getPersonalInfo = function(token) { - var self = this; - glideraService.getPersonalInfo(token, function(error, info) { - self.personalInfo = info; - }); - }; - - this.getStatus = function(token) { - var self = this; - glideraService.getStatus(token, function(error, data) { - self.status = data; - }); - }; - - this.getLimits = function(token) { - var self = this; - glideraService.getLimits(token, function(error, limits) { - self.limits = limits; - }); - }; - - this.revokeToken = function(testnet) { - $scope.network = testnet ? 'testnet' : 'livenet'; - $scope.loading = false; - - $ionicModal.fromTemplateUrl('views/modals/glidera-confirmation.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.glideraConfirmationModal = modal; - $scope.glideraConfirmationModal.show(); - }); - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesGlobalController', - function($scope, $rootScope, $log, configService, uxLanguage, platformInfo, pushNotificationsService, profileService, feeService) { - - var isCordova = platformInfo.isCordova; - - $scope.init = function() { - var config = configService.getSync(); - $scope.unitName = config.wallet.settings.unitName; - $scope.currentLanguageName = uxLanguage.getCurrentLanguageName(); - $scope.selectedAlternative = { - name: config.wallet.settings.alternativeName, - isoCode: config.wallet.settings.alternativeIsoCode - }; - $scope.feeOpts = feeService.feeOpts; - $scope.currentFeeLevel = feeService.getCurrentFeeLevel(); - $scope.usePushNotifications = isCordova && !platformInfo.isWP; - $scope.PNEnabledByUser = true; - $scope.isIOSApp = platformInfo.isIOS && isCordova; - if ($scope.isIOSApp) { - cordova.plugins.diagnostic.isRemoteNotificationsEnabled(function(isEnabled) { - $scope.PNEnabledByUser = isEnabled; - $scope.$digest(); - }); - } - $scope.spendUnconfirmed = config.wallet.spendUnconfirmed; - $scope.glideraEnabled = config.glidera.enabled; - $scope.coinbaseEnabled = config.coinbase.enabled; - $scope.pushNotifications = config.pushNotifications.enabled; - }; - - $scope.openSettings = function() { - cordova.plugins.diagnostic.switchToSettings(function() { - $log.debug('switched to settings'); - }, function(err) { - $log.debug(err); - }); - } - - $scope.spendUnconfirmedChange = function() { - var opts = { - wallet: { - spendUnconfirmed: $scope.spendUnconfirmed - } - }; - configService.set(opts, function(err) { - $rootScope.$emit('Local/SpendUnconfirmedUpdated', $scope.spendUnconfirmed); - if (err) $log.debug(err); - }); - }; - - $scope.pushNotificationsChange = function() { - var opts = { - pushNotifications: { - enabled: $scope.pushNotifications - } - }; - configService.set(opts, function(err) { - if (opts.pushNotifications.enabled) - pushNotificationsService.enableNotifications(profileService.walletClients); - else - pushNotificationsService.disableNotifications(profileService.walletClients); - if (err) $log.debug(err); - }); - }; - - $scope.glideraChange = function() { - var opts = { - glidera: { - enabled: $scope.glideraEnabled - } - }; - configService.set(opts, function(err) { - $rootScope.$emit('Local/GlideraUpdated'); - if (err) $log.debug(err); - }); - }; - - $scope.coinbaseChange = function() { - var opts = { - coinbase: { - enabled: $scope.coinbaseEnabled - } - }; - configService.set(opts, function(err) { - $rootScope.$emit('Local/CoinbaseUpdated'); - if (err) $log.debug(err); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesHistory', - function($scope, $log, $timeout, storageService, go, profileService, lodash) { - var fc = profileService.focusedClient; - var c = fc.credentials; - $scope.csvReady = false; - - $scope.csvHistory = function(cb) { - var allTxs = []; - - function getHistory(cb) { - storageService.getTxHistory(c.walletId, function(err, txs) { - if (err) return cb(err); - - var txsFromLocal = []; - try { - txsFromLocal = JSON.parse(txs); - } catch (ex) { - $log.warn(ex); - } - - allTxs.push(txsFromLocal); - return cb(null, lodash.flatten(allTxs)); - }); - }; - - $log.debug('Generating CSV from History'); - getHistory(function(err, txs) { - if (err || !txs) { - $log.warn('Failed to generate CSV:', err); - if (cb) return cb(err); - return; - } - - $log.debug('Wallet Transaction History Length:', txs.length); - - $scope.satToUnit = 1 / $scope.unitToSatoshi; - var data = txs; - var satToBtc = 1 / 100000000; - $scope.csvContent = []; - $scope.csvFilename = 'Copay-' + ($scope.alias || $scope.walletName) + '.csv'; - $scope.csvHeader = ['Date', 'Destination', 'Description', 'Amount', 'Currency', 'Txid', 'Creator', 'Copayers', 'Comment']; - - var _amount, _note, _copayers, _creator, _comment; - data.forEach(function(it, index) { - var amount = it.amount; - - if (it.action == 'moved') - amount = 0; - - _copayers = ''; - _creator = ''; - - if (it.actions && it.actions.length > 1) { - for (var i = 0; i < it.actions.length; i++) { - _copayers += it.actions[i].copayerName + ':' + it.actions[i].type + ' - '; - } - _creator = (it.creatorName && it.creatorName != 'undefined') ? it.creatorName : ''; - } - _amount = (it.action == 'sent' ? '-' : '') + (amount * satToBtc).toFixed(8); - _note = it.message || ''; - _comment = it.note ? it.note.body : ''; - - if (it.action == 'moved') - _note += ' Moved:' + (it.amount * satToBtc).toFixed(8) - - $scope.csvContent.push({ - 'Date': formatDate(it.time * 1000), - 'Destination': it.addressTo || '', - 'Description': _note, - 'Amount': _amount, - 'Currency': 'BTC', - 'Txid': it.txid, - 'Creator': _creator, - 'Copayers': _copayers, - 'Comment': _comment - }); - - if (it.fees && (it.action == 'moved' || it.action == 'sent')) { - var _fee = (it.fees * satToBtc).toFixed(8) - $scope.csvContent.push({ - 'Date': formatDate(it.time * 1000), - 'Destination': 'Bitcoin Network Fees', - 'Description': '', - 'Amount': '-' + _fee, - 'Currency': 'BTC', - 'Txid': '', - 'Creator': '', - 'Copayers': '' - }); - } - }); - - $scope.csvReady = true; - $timeout(function() { - $scope.$apply(); - }, 100); - - if (cb) - return cb(); - return; - }); - - function formatDate(date) { - var dateObj = new Date(date); - if (!dateObj) { - $log.debug('Error formating a date'); - return 'DateError' - } - if (!dateObj.toJSON()) { - return ''; - } - - return dateObj.toJSON(); - }; - }; - - $scope.clearTransactionHistory = function() { - storageService.removeTxHistory(c.walletId, function(err) { - if (err) { - $log.error(err); - return; - } - $scope.$emit('Local/ClearHistory'); - - $timeout(function() { - go.walletHome(); - }, 100); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesInformation', - function($scope, $log, $timeout, platformInfo, gettextCatalog, lodash, profileService, configService, go) { - var base = 'xpub'; - var fc = profileService.focusedClient; - var c = fc.credentials; - var walletId = c.walletId; - var config = configService.getSync(); - var b = 1; - var isCordova = platformInfo.isCordova; - config.colorFor = config.colorFor || {}; - - $scope.init = function() { - var basePath = c.getBaseAddressDerivationPath(); - - $scope.walletName = c.walletName; - $scope.walletId = c.walletId; - $scope.network = c.network; - $scope.addressType = c.addressType || 'P2SH'; - $scope.derivationStrategy = c.derivationStrategy || 'BIP45'; - $scope.basePath = basePath; - $scope.M = c.m; - $scope.N = c.n; - $scope.pubKeys = lodash.pluck(c.publicKeyRing, 'xPubKey'); - $scope.addrs = null; - - fc.getMainAddresses({ - doNotVerify: true - }, function(err, addrs) { - if (err) { - $log.warn(err); - return; - }; - var last10 = [], - i = 0, - e = addrs.pop(); - while (i++ < 10 && e) { - e.path = base + e.path.substring(1); - last10.push(e); - e = addrs.pop(); - } - $scope.addrs = last10; - $timeout(function() { - $scope.$apply(); - }); - - }); - }; - - $scope.sendAddrs = function() { - function formatDate(ts) { - var dateObj = new Date(ts * 1000); - if (!dateObj) { - $log.debug('Error formating a date'); - return 'DateError'; - } - if (!dateObj.toJSON()) { - return ''; - } - return dateObj.toJSON(); - }; - - $timeout(function() { - fc.getMainAddresses({ - doNotVerify: true - }, function(err, addrs) { - if (err) { - $log.warn(err); - return; - }; - - var body = 'Copay Wallet "' + $scope.walletName + '" Addresses\n Only Main Addresses are shown.\n\n'; - body += "\n"; - body += addrs.map(function(v) { - return ('* ' + v.address + ' ' + base + v.path.substring(1) + ' ' + formatDate(v.createdOn)); - }).join("\n"); - - window.plugins.socialsharing.shareViaEmail( - body, - 'Copay Addresses', - null, // TO: must be null or an array - null, // CC: must be null or an array - null, // BCC: must be null or an array - null, // FILES: can be null, a string, or an array - function() {}, - function() {} - ); - - $timeout(function() { - $scope.$apply(); - }, 1000); - }); - }, 100); - }; - - $scope.saveBlack = function() { - function save(color) { - var opts = { - colorFor: {} - }; - opts.colorFor[walletId] = color; - - configService.set(opts, function(err) { - go.walletHome(); - if (err) $log.warn(err); - $scope.$emit('Local/ColorUpdated'); - }); - }; - - if (b != 5) return b++; - save('#202020'); - }; - - $scope.copyToClipboard = function(data) { - if (isCordova) { - window.cordova.plugins.clipboard.copy(data); - window.plugins.toast.showShortCenter(gettextCatalog.getString('Copied to clipboard')); - } - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesLanguageController', - function($scope, $log, configService, profileService, uxLanguage, walletService, go) { - - $scope.availableLanguages = uxLanguage.getLanguages(); - $scope.currentLanguage = uxLanguage.getCurrentLanguage(); - - $scope.save = function(newLang) { - var opts = { - wallet: { - settings: { - defaultLanguage: newLang - } - } - }; - - configService.set(opts, function(err) { - if (err) $log.warn(err); - go.preferencesGlobal(); - - uxLanguage.update(function() { - walletService.updateRemotePreferences(profileService.getClients(), {}, function() { - $log.debug('Remote preferences saved'); - }); - }); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesLogs', -function(historicLog) { - this.logs = historicLog.get(); - - this.sendLogs = function() { - var body = 'Copay Session Logs\n Be careful, this could contain sensitive private data\n\n'; - body += '\n\n'; - body += this.logs.map(function(v) { - return v.msg; - }).join('\n'); - - window.plugins.socialsharing.shareViaEmail( - body, - 'Copay Logs', - null, // TO: must be null or an array - null, // CC: must be null or an array - null, // BCC: must be null or an array - null, // FILES: can be null, a string, or an array - function() {}, - function() {} - ); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('preferencesUnitController', function($scope, $log, configService, go, walletService, profileService) { - - var config = configService.getSync(); - - $scope.currentUnit = config.wallet.settings.unitCode; - - $scope.unitList = [ - { - name: 'bits (1,000,000 bits = 1BTC)', - shortName: 'bits', - value: 100, - decimals: 2, - code: 'bit', - }, - { - name: 'BTC', - shortName: 'BTC', - value: 100000000, - decimals: 8, - code: 'btc', - } - ]; - - $scope.save = function(newUnit) { - var opts = { - wallet: { - settings: { - unitName: newUnit.shortName, - unitToSatoshi: newUnit.value, - unitDecimals: newUnit.decimals, - unitCode: newUnit.code, - } - } - }; - - configService.set(opts, function(err) { - if (err) $log.warn(err); - - go.preferencesGlobal(); - $scope.$emit('Local/UnitSettingUpdated'); - - walletService.updateRemotePreferences(profileService.getClients(), {}, function() { - $log.debug('Remote preferences saved'); - }); - }); - }; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('sellCoinbaseController', - function($rootScope, $scope, $log, $timeout, $ionicModal, lodash, profileService, coinbaseService, configService, walletService, fingerprintService, ongoingProcess, go) { - - var self = this; - var client; - - $scope.priceSensitivity = [ - { - value: 0.5, - name: '0.5%' - }, - { - value: 1, - name: '1%' - }, - { - value: 2, - name: '2%' - }, - { - value: 5, - name: '5%' - }, - { - value: 10, - name: '10%' - } - ]; - $scope.selectedPriceSensitivity = $scope.priceSensitivity[1]; - - var handleEncryptedWallet = function(client, cb) { - if (!walletService.isEncrypted(client)) return cb(); - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - - this.init = function(testnet) { - self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1); - - client = profileService.focusedClient; - if (client && client.credentials.m == 1) { - $timeout(function() { - self.selectedWalletId = client.credentials.walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - } - }; - - this.getPaymentMethods = function(token) { - coinbaseService.getPaymentMethods(token, function(err, p) { - if (err) { - self.error = err; - return; - } - self.paymentMethods = []; - lodash.each(p.data, function(pm) { - if (pm.allow_sell) { - self.paymentMethods.push(pm); - } - if (pm.allow_sell && pm.primary_sell) { - $scope.selectedPaymentMethod = pm; - } - }); - }); - }; - - this.getPrice = function(token) { - var currency = 'USD'; - coinbaseService.sellPrice(token, currency, function(err, s) { - if (err) return; - self.sellPrice = s.data || null; - }); - }; - - $scope.openWalletsModal = function(wallets) { - self.error = null; - - $scope.type = 'SELL'; - $scope.wallets = wallets; - $scope.noColor = true; - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/wallets.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.walletsModal = modal; - $scope.walletsModal.show(); - }); - - $scope.$on('walletSelected', function(ev, walletId) { - $timeout(function() { - client = profileService.getClient(walletId); - self.selectedWalletId = walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - $scope.walletsModal.hide(); - }); - }; - - this.depositFunds = function(token, account) { - self.error = null; - if ($scope.amount) { - this.createTx(token, account, $scope.amount) - } else if ($scope.fiat) { - var btcValue = ($scope.fiat / self.sellPrice.amount).toFixed(8); - this.createTx(token, account, btcValue); - } - }; - - this.sellRequest = function(token, account, ctx) { - self.error = null; - if (!ctx.amount) return; - var accountId = account.id; - var data = ctx.amount; - data['payment_method'] = $scope.selectedPaymentMethod.id || null; - ongoingProcess.set('Sending request...', true); - coinbaseService.sellRequest(token, accountId, data, function(err, sell) { - ongoingProcess.set('Sending request...', false); - if (err) { - self.error = err; - return; - } - self.sellInfo = sell.data; - }); - }; - - this.confirmSell = function(token, account, sell) { - self.error = null; - var accountId = account.id; - var sellId = sell.id; - ongoingProcess.set('Selling Bitcoin...', true); - coinbaseService.sellCommit(token, accountId, sellId, function(err, data) { - ongoingProcess.set('Selling Bitcoin...', false); - if (err) { - self.error = err; - return; - } - self.success = data.data; - $scope.$emit('Local/CoinbaseTx'); - }); - }; - - this.createTx = function(token, account, amount) { - self.error = null; - - if (!client) { - self.error = 'No wallet selected'; - return; - } - - var accountId = account.id; - var dataSrc = { - name: 'Received from Copay: ' + self.selectedWalletName - }; - var outputs = []; - var config = configService.getSync(); - var configWallet = config.wallet; - var walletSettings = configWallet.settings; - - - ongoingProcess.set('Creating Transaction...', true); - $timeout(function() { - - coinbaseService.createAddress(token, accountId, dataSrc, function(err, data) { - if (err) { - ongoingProcess.set('Creating Transaction...', false); - self.error = err; - return; - } - - var address, comment; - - address = data.data.address; - amount = parseInt((amount * 100000000).toFixed(0)); - comment = 'Send funds to Coinbase Account: ' + account.name; - - outputs.push({ - 'toAddress': address, - 'amount': amount, - 'message': comment - }); - - var txp = { - toAddress: address, - amount: amount, - outputs: outputs, - message: comment, - payProUrl: null, - excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, - feeLevel: walletSettings.feeLevel || 'normal' - }; - - walletService.createTx(client, txp, function(err, createdTxp) { - if (err) { - $log.debug(err); - ongoingProcess.set('Creating Transaction...', false); - self.error = { - errors: [{ - message: 'Could not create transaction: ' + err.message - }] - }; - $scope.$apply(); - return; - } - ongoingProcess.set('Creating Transaction...', false); - $scope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) { - if (accept) { - self.confirmTx(createdTxp, function(err, tx) { - ongoingProcess.clear(); - if (err) { - self.error = { - errors: [{ - message: 'Could not create transaction: ' + err.message - }] - }; - return; - } - ongoingProcess.set('Checking Transaction...', false); - coinbaseService.getTransactions(token, accountId, function(err, ctxs) { - if (err) { - $log.debug(err); - return; - } - lodash.each(ctxs.data, function(ctx) { - if (ctx.type == 'send' && ctx.from) { - ongoingProcess.clear(); - if (ctx.status == 'completed') { - self.sellRequest(token, account, ctx); - } else { - // Save to localstorage - ctx['price_sensitivity'] = $scope.selectedPriceSensitivity; - ctx['sell_price_amount'] = self.sellPrice ? self.sellPrice.amount : ''; - ctx['sell_price_currency'] = self.sellPrice ? self.sellPrice.currency : 'USD'; - ctx['description'] = 'Copay Wallet: ' + client.credentials.walletName; - coinbaseService.savePendingTransaction(ctx, null, function(err) { - if (err) $log.debug(err); - self.sendInfo = ctx; - $timeout(function() { - $scope.$emit('Local/CoinbaseTx'); - }, 1000); - }); - } - return false; - } - }); - }); - }); - } else { - go.path('coinbase'); - } - }); - }); - }); - }, 100); - }; - - this.confirmTx = function(txp, cb) { - - fingerprintService.check(client, function(err) { - if (err) { - $log.debug(err); - return cb(err); - } - - handleEncryptedWallet(client, function(err) { - if (err) { - $log.debug(err); - return cb(err); - } - - ongoingProcess.set('Sending Bitcoin to Coinbase...', true); - walletService.publishTx(client, txp, function(err, publishedTxp) { - if (err) { - ongoingProcess.set('Sending Bitcoin to Coinbase...', false); - $log.debug(err); - return cb({ - errors: [{ - message: 'Transaction could not be published: ' + err.message - }] - }); - } - - walletService.signTx(client, publishedTxp, function(err, signedTxp) { - walletService.lock(client); - if (err) { - ongoingProcess.set('Sending Bitcoin to Coinbase...', false); - $log.debug(err); - walletService.removeTx(client, signedTxp, function(err) { - if (err) $log.debug(err); - }); - return cb({ - errors: [{ - message: 'The payment was created but could not be completed: ' + err.message - }] - }); - } - - walletService.broadcastTx(client, signedTxp, function(err, broadcastedTxp) { - if (err) { - ongoingProcess.set('Sending Bitcoin to Coinbase...', false); - $log.debug(err); - walletService.removeTx(client, broadcastedTxp, function(err) { - if (err) $log.debug(err); - }); - return cb({ - errors: [{ - message: 'The payment was created but could not be broadcasted: ' + err.message - }] - }); - } - $timeout(function() { - return cb(null, broadcastedTxp); - }, 5000); - }); - }); - }); - }); - }); - }; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('sellGlideraController', - function($rootScope, $scope, $timeout, $ionicModal, $log, configService, profileService, addressService, feeService, glideraService, bwcError, lodash, walletService, fingerprintService, ongoingProcess, go) { - - var self = this; - var config = configService.getSync(); - this.data = {}; - this.show2faCodeInput = null; - this.success = null; - this.error = null; - var client; - - var handleEncryptedWallet = function(client, cb) { - if (!walletService.isEncrypted(client)) return cb(); - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - - this.init = function(testnet) { - self.allWallets = profileService.getWallets(testnet ? 'testnet' : 'livenet', 1); - - client = profileService.focusedClient; - if (client && client.credentials.m == 1) { - $timeout(function() { - self.selectedWalletId = client.credentials.walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - } - }; - - - - $scope.openWalletsModal = function(wallets) { - self.error = null; - - $scope.type = 'SELL'; - $scope.wallets = wallets; - $scope.noColor = true; - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/wallets.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.walletsModal = modal; - $scope.walletsModal.show(); - }); - - $scope.$on('walletSelected', function(ev, walletId) { - $timeout(function() { - client = profileService.getClient(walletId); - self.selectedWalletId = walletId; - self.selectedWalletName = client.credentials.walletName; - $scope.$apply(); - }, 100); - $scope.walletsModal.hide(); - }); - }; - - this.getSellPrice = function(token, price) { - var self = this; - self.error = null; - if (!price || (price && !price.qty && !price.fiat)) { - self.sellPrice = null; - return; - } - self.gettingSellPrice = true; - glideraService.sellPrice(token, price, function(err, sellPrice) { - self.gettingSellPrice = false; - if (err) { - self.error = 'Could not get exchange information. Please, try again.'; - return; - } - self.sellPrice = sellPrice; - }); - }; - - this.get2faCode = function(token) { - var self = this; - ongoingProcess.set('Sending 2FA code...', true); - $timeout(function() { - glideraService.get2faCode(token, function(err, sent) { - ongoingProcess.set('Sending 2FA code...', false); - if (err) { - self.error = 'Could not send confirmation code to your phone'; - } else { - self.show2faCodeInput = sent; - } - }); - }, 100); - }; - - this.createTx = function(token, permissions, twoFaCode) { - var self = this; - self.error = null; - var outputs = []; - var configWallet = config.wallet; - var walletSettings = configWallet.settings; - - if (!client) { - self.error = 'No wallet selected'; - return; - } - - ongoingProcess.set('creatingTx', true); - addressService.getAddress(client.credentials.walletId, null, function(err, refundAddress) { - if (!refundAddress) { - - ongoingProcess.clear(); - self.error = bwcError.msg(err, 'Could not create address'); - return; - } - glideraService.getSellAddress(token, function(error, sellAddress) { - if (!sellAddress) { - ongoingProcess.clear(); - self.error = 'Could not get the destination bitcoin address'; - return; - } - var amount = parseInt((self.sellPrice.qty * 100000000).toFixed(0)); - var comment = 'Glidera transaction'; - - outputs.push({ - 'toAddress': sellAddress, - 'amount': amount, - 'message': comment - }); - - var txp = { - toAddress: sellAddress, - amount: amount, - outputs: outputs, - message: comment, - payProUrl: null, - excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true, - feeLevel: walletSettings.feeLevel || 'normal', - customData: { - 'glideraToken': token - } - }; - - walletService.createTx(client, txp, function(err, createdTxp) { - ongoingProcess.clear(); - if (err) { - self.error = err.message ||  bwcError.msg(err); - return; - } - $scope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) { - if (accept) { - fingerprintService.check(client, function(err) { - if (err) { - self.error = err.message ||  bwcError.msg(err); - return; - } - - handleEncryptedWallet(client, function(err) { - if (err) { - self.error = err.message ||  bwcError.msg(err); - return; - } - - ongoingProcess.set('signingTx', true); - walletService.publishTx(client, createdTxp, function(err, publishedTxp) { - if (err) { - ongoingProcess.clear(); - self.error = err.message ||  bwcError.msg(err); - } - - walletService.signTx(client, publishedTxp, function(err, signedTxp) { - walletService.lock(client); - walletService.removeTx(client, signedTxp, function(err) { - if (err) $log.debug(err); - }); - ongoingProcess.clear(); - if (err) { - self.error = err.message ||  bwcError.msg(err); - return; - } - var rawTx = signedTxp.raw; - var data = { - refundAddress: refundAddress, - signedTransaction: rawTx, - priceUuid: self.sellPrice.priceUuid, - useCurrentPrice: self.sellPrice.priceUuid ? false : true, - ip: null - }; - ongoingProcess.set('Seling Bitcoin', true); - glideraService.sell(token, twoFaCode, data, function(err, data) { - ongoingProcess.clear(); - if (err) { - self.error = err.message ||  bwcError.msg(err); - $timeout(function() { - $scope.$emit('Local/GlideraError'); - }, 100); - return; - } - self.success = data; - $scope.$emit('Local/GlideraTx'); - }); - }); - }); - }); - }); - } else { - go.path('glidera'); - } - }); - }); - }); - }); - }; - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('sidebarController', - function($rootScope, $timeout, $ionicScrollDelegate, lodash, profileService, configService, go, platformInfo) { - var self = this; - self.isWindowsPhoneApp = platformInfo.isWP && platformInfo.isCordova; - self.walletSelection = false; - - // wallet list change - $rootScope.$on('Local/WalletListUpdated', function(event) { - self.walletSelection = false; - self.setWallets(); - }); - - $rootScope.$on('Local/ColorUpdated', function(event) { - self.setWallets(); - }); - - $rootScope.$on('Local/AliasUpdated', function(event) { - self.setWallets(); - }); - - self.signout = function() { - profileService.signout(); - }; - - self.switchWallet = function(selectedWalletId, currentWalletId) { - var client = profileService.focusedClient; - if (selectedWalletId == currentWalletId && client.isComplete()) return; - self.walletSelection = false; - profileService.setAndStoreFocus(selectedWalletId, function() {}); - $ionicScrollDelegate.scrollTop(); - }; - - self.toggleWalletSelection = function() { - self.walletSelection = !self.walletSelection; - if (!self.walletSelection) return; - self.setWallets(); - }; - - self.setWallets = function() { - if (!profileService.profile) return; - - var config = configService.getSync(); - config.colorFor = config.colorFor || {}; - config.aliasFor = config.aliasFor || {}; - - // Sanitize empty wallets (fixed in BWC 1.8.1, and auto fixed when wallets completes) - var credentials = lodash.filter(profileService.profile.credentials, 'walletName'); - var ret = lodash.map(credentials, function(c) { - return { - m: c.m, - n: c.n, - name: config.aliasFor[c.walletId] || c.walletName, - id: c.walletId, - color: config.colorFor[c.walletId] || '#4A90E2', - }; - }); - - self.wallets = lodash.sortBy(ret, 'name'); - }; - - self.setWallets(); - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('termOfUseController', - function($scope, uxLanguage) { - - $scope.lang = uxLanguage.currentLanguage; - - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('topbarController', function(go) { - - this.goHome = function() { - go.walletHome(); - }; - - this.goPreferences = function() { - go.preferences(); - }; - -}); - -'use strict'; -angular.module('copayApp.controllers').controller('uriController', - function($stateParams, $log, openURLService) { - - - /* This is only for BROWSER links, it is not excecuted on mobile devices */ - - $log.info('DEEP LINK from Browser:' + $stateParams.url); - openURLService.handleURL({ - url: $stateParams.url - }); - }); - -'use strict'; - -angular.module('copayApp.controllers').controller('versionController', function() { - this.version = window.version; - this.commitHash = window.commitHash; -}); - -'use strict'; - -angular.module('copayApp.controllers').controller('walletHomeController', function($scope, $rootScope, $interval, $timeout, $filter, $log, $ionicModal, notification, txStatus, profileService, lodash, configService, rateService, storageService, bitcore, gettext, gettextCatalog, platformInfo, addressService, ledger, bwcError, confirmDialog, txFormatService, addressbookService, go, feeService, walletService, fingerprintService, nodeWebkit, ongoingProcess) { - - var isCordova = platformInfo.isCordova; - var isWP = platformInfo.isWP; - var isAndroid = platformInfo.isAndroid; - var isChromeApp = platformInfo.isChromeApp; - - var self = this; - $rootScope.shouldHideMenuBar = false; - $rootScope.wpInputFocused = false; - var config = configService.getSync(); - var configWallet = config.wallet; - var walletSettings = configWallet.settings; - var ret = {}; - - // INIT. Global value - ret.unitToSatoshi = walletSettings.unitToSatoshi; - ret.satToUnit = 1 / ret.unitToSatoshi; - ret.unitName = walletSettings.unitName; - ret.alternativeIsoCode = walletSettings.alternativeIsoCode; - ret.alternativeName = walletSettings.alternativeName; - ret.alternativeAmount = 0; - ret.unitDecimals = walletSettings.unitDecimals; - ret.isCordova = isCordova; - ret.addresses = []; - ret.isMobile = platformInfo.isMobile; - ret.isWindowsPhoneApp = platformInfo.isWP; - ret.countDown = null; - ret.sendMaxInfo = {}; - var vanillaScope = ret; - - var disableScannerListener = $rootScope.$on('dataScanned', function(event, data) { - if (!data) return; - - self.setForm(data); - $rootScope.$emit('Local/SetTab', 'send'); - var form = $scope.sendForm; - if (form.address.$invalid && !ongoingProcess.get('fetchingPayPro')) { - self.resetForm(); - self.error = gettext('Could not recognize a valid Bitcoin QR Code'); - } - }); - - var disablePaymentUriListener = $rootScope.$on('paymentUri', function(event, uri) { - $rootScope.$emit('Local/SetTab', 'send'); - $timeout(function() { - self.setForm(uri); - }, 100); - }); - - var disableAddrListener = $rootScope.$on('Local/AddressIsUsed', function() { - self.setAddress(true); - }); - - var disableFocusListener = $rootScope.$on('Local/NewFocusedWalletReady', function() { - self.addr = null; - self.resetForm(); - $scope.search = ''; - - if (profileService.focusedClient && profileService.focusedClient.isComplete()) { - self.setAddress(); - self.setSendFormInputs(); - } - - $log.debug('Cleaning WalletHome Instance'); - lodash.each(self, function(v, k) { - if (lodash.isFunction(v)) return; - if (!lodash.isUndefined(vanillaScope[k])) { - self[k] = vanillaScope[k]; - return; - } - if (k == 'isRateAvailable') return; - - delete self[k]; - }); - }); - - var disableResumeListener = $rootScope.$on('Local/Resume', function() { - // This is needed then the apps go to sleep - self.bindTouchDown(); - }); - - var disableTabListener = $rootScope.$on('Local/TabChanged', function(e, tab) { - // This will slow down switch, do not add things here! - switch (tab) { - case 'receive': - // just to be sure we have an address - self.setAddress(); - break; - case 'send': - self.resetError(); - }; - }); - - $scope.$on('$destroy', function() { - disableAddrListener(); - disableScannerListener(); - disablePaymentUriListener(); - disableTabListener(); - disableFocusListener(); - disableResumeListener(); - $rootScope.shouldHideMenuBar = false; - }); - - this.onQrCodeScanned = function(data) { - if (data) go.send(); - $rootScope.$emit('dataScanned', data); - }; - - rateService.whenAvailable(function() { - self.isRateAvailable = true; - $rootScope.$digest(); - }); - - var getClipboard = function(cb) { - if (!isCordova || platformInfo.isWP) return cb(); - - window.cordova.plugins.clipboard.paste(function(value) { - var fc = profileService.focusedClient; - var Address = bitcore.Address; - var networkName = fc.credentials.network; - if (Address.isValid(value, networkName) && !$scope.newAddress) { - return cb(value); - } - }); - }; - - var handleEncryptedWallet = function(client, cb) { - if (!walletService.isEncrypted(client)) return cb(); - $rootScope.$emit('Local/NeedsPassword', false, function(err, password) { - if (err) return cb(err); - return cb(walletService.unlock(client, password)); - }); - }; - - var accept_msg = gettextCatalog.getString('Accept'); - var cancel_msg = gettextCatalog.getString('Cancel'); - var confirm_msg = gettextCatalog.getString('Confirm'); - - this.openAddressbookModal = function(wallets, address) { - $scope.wallets = wallets; - $scope.address = address; - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/addressbook.html', { - scope: $scope - }).then(function(modal) { - $scope.addressbookModal = modal; - $scope.addressbookModal.show(); - }); - }; - - var GLIDERA_LOCK_TIME = 6 * 60 * 60; - // isGlidera flag is a security measure so glidera status is not - // only determined by the tx.message - this.openTxpModal = function(tx, copayers, isGlidera) { - $scope.self = self; - $scope.tx = tx; - $scope.copayers = copayers; - $scope.isGlidera = isGlidera; - $scope.error = null; - $scope.loading = null; - $scope.paymentExpired = null; - $scope.currentSpendUnconfirmed = configWallet.spendUnconfirmed; - - $ionicModal.fromTemplateUrl('views/modals/txp-details.html', { - scope: $scope - }).then(function(modal) { - $scope.txpDetailsModal = modal; - $scope.txpDetailsModal.show(); - }); - }; - - this.setAddress = function(forceNew) { - self.addrError = null; - var client = profileService.focusedClient; - if (!client || !client.isComplete()) return; - - // Address already set? - if (!forceNew && self.addr) { - return; - } - - self.generatingAddress = true; - $timeout(function() { - addressService.getAddress(client.credentials.walletId, forceNew, function(err, addr) { - self.generatingAddress = false; - - if (err) { - self.addrError = err; - } else { - if (addr) - self.addr = addr; - } - - $scope.$digest(); - }); - }); - }; - - this.copyToClipboard = function(addr) { - if (isCordova) { - window.cordova.plugins.clipboard.copy(addr); - window.plugins.toast.showShortCenter(gettextCatalog.getString('Copied to clipboard')); - } else if (platformInfo.isNW) { - nodeWebkit.writeToClipboard(addr); - } - }; - - this.shareAddress = function(addr) { - if (isCordova) { - window.plugins.socialsharing.share('bitcoin:' + addr, null, null, null); - } - }; - - this.openCustomizedAmountModal = function(addr) { - var fc = profileService.focusedClient; - - $scope.color = fc.backgroundColor; - $scope.self = self; - $scope.addr = addr; - - $ionicModal.fromTemplateUrl('views/modals/customized-amount.html', { - scope: $scope - }).then(function(modal) { - $scope.customAmountModal = modal; - $scope.customAmountModal.show(); - }); - }; - - // Send - - this.canShowAlternative = function() { - return $scope.showAlternative; - }; - - this.showAlternative = function() { - $scope.showAlternative = true; - }; - - this.hideAlternative = function() { - $scope.showAlternative = false; - }; - - this.resetError = function() { - this.error = this.success = null; - }; - - this.bindTouchDown = function(tries) { - var self = this; - tries = tries || 0; - if (tries > 5) return; - var e = document.getElementById('menu-walletHome'); - if (!e) return $timeout(function() { - self.bindTouchDown(++tries); - }, 500); - - // on touchdown elements - $log.debug('Binding touchstart elements...'); - ['hamburger', 'menu-walletHome', 'menu-send', 'menu-receive'].forEach(function(id) { - var e = document.getElementById(id); - if (e) e.addEventListener('touchstart', function() { - try { - event.preventDefault(); - } catch (e) {}; - angular.element(e).triggerHandler('click'); - }, true); - }); - } - - this.hideMenuBar = lodash.debounce(function(hide) { - if (hide) { - $rootScope.shouldHideMenuBar = true; - } else { - $rootScope.shouldHideMenuBar = false; - } - $rootScope.$digest(); - }, 100); - - this.formFocus = function(what) { - if (isCordova && this.isWindowsPhoneApp) { - this.hideMenuBar(what); - } - var self = this; - if (isCordova && !this.isWindowsPhoneApp && what == 'address') { - getClipboard(function(value) { - if (value) { - document.getElementById("amount").focus(); - $timeout(function() { - window.plugins.toast.showShortCenter(gettextCatalog.getString('Pasted from clipboard')); - self.setForm(value); - }, 100); - } - }); - } - }; - - this.setSendFormInputs = function() { - var unitToSat = this.unitToSatoshi; - var satToUnit = 1 / unitToSat; - /** - * Setting the two related amounts as properties prevents an infinite - * recursion for watches while preserving the original angular updates - * - */ - Object.defineProperty($scope, - "_alternative", { - get: function() { - return $scope.__alternative; - }, - set: function(newValue) { - $scope.__alternative = newValue; - if (typeof(newValue) === 'number' && self.isRateAvailable) { - $scope._amount = parseFloat((rateService.fromFiat(newValue, self.alternativeIsoCode) * satToUnit).toFixed(self.unitDecimals), 10); - } else { - $scope.__amount = null; - } - }, - enumerable: true, - configurable: true - }); - Object.defineProperty($scope, - "_amount", { - get: function() { - return $scope.__amount; - }, - set: function(newValue) { - $scope.__amount = newValue; - if (typeof(newValue) === 'number' && self.isRateAvailable) { - $scope.__alternative = parseFloat((rateService.toFiat(newValue * self.unitToSatoshi, self.alternativeIsoCode)).toFixed(2), 10); - } else { - $scope.__alternative = null; - } - self.alternativeAmount = $scope.__alternative; - self.resetError(); - }, - enumerable: true, - configurable: true - }); - - Object.defineProperty($scope, - "_address", { - get: function() { - return $scope.__address; - }, - set: function(newValue) { - $scope.__address = self.onAddressChange(newValue); - if ($scope.sendForm && $scope.sendForm.address.$valid) { - self.lockAddress = true; - } - }, - enumerable: true, - configurable: true - }); - - var fc = profileService.focusedClient; - // ToDo: use a credential's (or fc's) function for this - this.hideNote = !fc.credentials.sharedEncryptingKey; - }; - - this.setSendError = function(err) { - var fc = profileService.focusedClient; - var prefix = - fc.credentials.m > 1 ? gettextCatalog.getString('Could not create payment proposal') : gettextCatalog.getString('Could not send payment'); - - this.error = bwcError.msg(err, prefix); - - $timeout(function() { - $scope.$digest(); - }, 1); - }; - - this.submitForm = function() { - if (!$scope._amount || !$scope._address) return; - var client = profileService.focusedClient; - var unitToSat = this.unitToSatoshi; - var currentSpendUnconfirmed = configWallet.spendUnconfirmed; - - var outputs = []; - - this.resetError(); - - if (isCordova && this.isWindowsPhoneApp) - $rootScope.shouldHideMenuBar = true; - - var form = $scope.sendForm; - var comment = form.comment.$modelValue; - - // ToDo: use a credential's (or fc's) function for this - if (comment && !client.credentials.sharedEncryptingKey) { - var msg = 'Could not add message to imported wallet without shared encrypting key'; - $log.warn(msg); - return self.setSendError(gettext(msg)); - } - - if (form.amount.$modelValue * unitToSat > Number.MAX_SAFE_INTEGER) { - var msg = 'Amount too big'; - $log.warn(msg); - return self.setSendError(gettext(msg)); - }; - - $timeout(function() { - var paypro = self._paypro; - var address, amount; - - address = form.address.$modelValue; - amount = parseInt((form.amount.$modelValue * unitToSat).toFixed(0)); - - outputs.push({ - 'toAddress': address, - 'amount': amount, - 'message': comment - }); - - var txp = {}; - - if (!lodash.isEmpty(self.sendMaxInfo)) { - txp.sendMax = true; - txp.inputs = self.sendMaxInfo.inputs; - txp.fee = self.sendMaxInfo.fee; - } else { - txp.amount = amount; - } - - txp.toAddress = address; - txp.outputs = outputs; - txp.message = comment; - txp.payProUrl = paypro ? paypro.url : null; - txp.excludeUnconfirmedUtxos = configWallet.spendUnconfirmed ? false : true; - txp.feeLevel = walletSettings.feeLevel || 'normal'; - - ongoingProcess.set('creatingTx', true); - walletService.createTx(client, txp, function(err, createdTxp) { - ongoingProcess.set('creatingTx', false); - if (err) { - return self.setSendError(err); - } - - if (!client.canSign() && !client.isPrivKeyExternal()) { - $log.info('No signing proposal: No private key'); - ongoingProcess.set('sendingTx', true); - walletService.publishTx(client, createdTxp, function(err, publishedTxp) { - ongoingProcess.set('sendingTx', false); - if (err) { - return self.setSendError(err); - } - self.resetForm(); - go.walletHome(); - var type = txStatus.notify(createdTxp); - $scope.openStatusModal(type, createdTxp, function() { - return $scope.$emit('Local/TxProposalAction'); - }); - }); - } else { - $rootScope.$emit('Local/NeedsConfirmation', createdTxp, function(accept) { - if (accept) self.confirmTx(createdTxp); - else self.resetForm(); - }); - } - }); - - }, 100); - }; - - this.confirmTx = function(txp) { - var client = profileService.focusedClient; - var self = this; - - fingerprintService.check(client, function(err) { - if (err) { - return self.setSendError(err); - } - - handleEncryptedWallet(client, function(err) { - if (err) { - return self.setSendError(err); - } - - ongoingProcess.set('sendingTx', true); - walletService.publishTx(client, txp, function(err, publishedTxp) { - ongoingProcess.set('sendingTx', false); - if (err) { - return self.setSendError(err); - } - - ongoingProcess.set('signingTx', true); - walletService.signTx(client, publishedTxp, function(err, signedTxp) { - ongoingProcess.set('signingTx', false); - walletService.lock(client); - if (err) { - $scope.$emit('Local/TxProposalAction'); - return self.setSendError( - err.message ? - err.message : - gettext('The payment was created but could not be completed. Please try again from home screen')); - } - - if (signedTxp.status == 'accepted') { - ongoingProcess.set('broadcastingTx', true); - walletService.broadcastTx(client, signedTxp, function(err, broadcastedTxp) { - ongoingProcess.set('broadcastingTx', false); - if (err) { - return self.setSendError(err); - } - self.resetForm(); - go.walletHome(); - var type = txStatus.notify(broadcastedTxp); - $scope.openStatusModal(type, broadcastedTxp, function() { - $scope.$emit('Local/TxProposalAction', broadcastedTxp.status == 'broadcasted'); - }); - }); - } else { - self.resetForm(); - go.walletHome(); - var type = txStatus.notify(signedTxp); - $scope.openStatusModal(type, signedTxp, function() { - $scope.$emit('Local/TxProposalAction'); - }); - } - }); - }); - }); - }); - }; - - $scope.openStatusModal = function(type, txp, cb) { - var fc = profileService.focusedClient; - $scope.type = type; - $scope.tx = txFormatService.processTx(txp); - $scope.color = fc.backgroundColor; - $scope.cb = cb; - - $ionicModal.fromTemplateUrl('views/modals/tx-status.html', { - scope: $scope, - animation: 'slide-in-up' - }).then(function(modal) { - $scope.txStatusModal = modal; - $scope.txStatusModal.show(); - }); - }; - - $scope.openSearchModal = function() { - var fc = profileService.focusedClient; - $scope.color = fc.backgroundColor; - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/search.html', { - scope: $scope, - focusFirstInput: true - }).then(function(modal) { - $scope.searchModal = modal; - $scope.searchModal.show(); - }); - }; - - this.setForm = function(to, amount, comment) { - var form = $scope.sendForm; - if (to) { - form.address.$setViewValue(to); - form.address.$isValid = true; - form.address.$render(); - this.lockAddress = true; - } - - if (amount) { - form.amount.$setViewValue("" + amount); - form.amount.$isValid = true; - form.amount.$render(); - this.lockAmount = true; - } - - if (comment) { - form.comment.$setViewValue(comment); - form.comment.$isValid = true; - form.comment.$render(); - } - }; - - this.resetForm = function() { - this.resetError(); - this.sendMaxInfo = {}; - if (this.countDown) $interval.cancel(this.countDown); - this._paypro = null; - - this.lockAddress = false; - this.lockAmount = false; - - this._amount = this._address = null; - - var form = $scope.sendForm; - - if (form && form.amount) { - form.amount.$pristine = true; - form.amount.$setViewValue(''); - form.amount.$render(); - - form.comment.$setViewValue(''); - form.comment.$render(); - form.$setPristine(); - - if (form.address) { - form.address.$pristine = true; - form.address.$setViewValue(''); - form.address.$render(); - } - } - $timeout(function() { - $rootScope.$digest(); - }, 1); - }; - - this.openPPModal = function(paypro) { - var fc = profileService.focusedClient; - $scope.color = fc.backgroundColor; - $scope.self = self; - $scope.paypro = paypro; - - $ionicModal.fromTemplateUrl('views/modals/paypro.html', { - scope: $scope - }).then(function(modal) { - $scope.payproModal = modal; - $scope.payproModal.show(); - }); - }; - - this.setFromPayPro = function(uri, cb) { - if (!cb) cb = function() {}; - - var fc = profileService.focusedClient; - if (isChromeApp) { - this.error = gettext('Payment Protocol not supported on Chrome App'); - return cb(true); - } - - var satToUnit = 1 / this.unitToSatoshi; - var self = this; - /// Get information of payment if using Payment Protocol - ongoingProcess.set('fetchingPayPro', true); - - $log.debug('Fetch PayPro Request...', uri); - $timeout(function() { - fc.fetchPayPro({ - payProUrl: uri, - }, function(err, paypro) { - ongoingProcess.set('fetchingPayPro', false); - - if (err) { - $log.warn('Could not fetch payment request:', err); - self.resetForm(); - var msg = err.toString(); - if (msg.match('HTTP')) { - msg = gettext('Could not fetch payment information'); - } - self.error = msg; - $timeout(function() { - $rootScope.$digest(); - }, 1); - return cb(true); - } - - if (!paypro.verified) { - self.resetForm(); - $log.warn('Failed to verify payment protocol signatures'); - self.error = gettext('Payment Protocol Invalid'); - $timeout(function() { - $rootScope.$digest(); - }, 1); - return cb(true); - } - - self._paypro = paypro; - self.setForm(paypro.toAddress, (paypro.amount * satToUnit).toFixed(self.unitDecimals), paypro.memo); - _paymentTimeControl(paypro.expires); - return cb(); - }); - }, 1); - }; - - function _paymentTimeControl(expirationTime) { - self.paymentExpired = false; - setExpirationTime(); - - self.countDown = $interval(function() { - setExpirationTime(); - }, 1000); - - function setExpirationTime() { - var now = Math.floor(Date.now() / 1000); - if (now > expirationTime) { - setExpiredValues(); - return; - } - - var totalSecs = expirationTime - now; - var m = Math.floor(totalSecs / 60); - var s = totalSecs % 60; - self.remainingTimeStr = ('0' + m).slice(-2) + ":" + ('0' + s).slice(-2); - }; - - function setExpiredValues() { - self.paymentExpired = true; - self.remainingTimeStr = null; - self._paypro = null; - self.error = gettext('Cannot sign: The payment request has expired'); - if (self.countDown) $interval.cancel(self.countDown); - }; - }; - - this.setFromUri = function(uri) { - var self = this; - - function sanitizeUri(uri) { - // Fixes when a region uses comma to separate decimals - var regex = /[\?\&]amount=(\d+([\,\.]\d+)?)/i; - var match = regex.exec(uri); - if (!match || match.length === 0) { - return uri; - } - var value = match[0].replace(',', '.'); - var newUri = uri.replace(regex, value); - return newUri; - }; - - var satToUnit = 1 / this.unitToSatoshi; - - // URI extensions for Payment Protocol with non-backwards-compatible request - if ((/^bitcoin:\?r=[\w+]/).exec(uri)) { - uri = decodeURIComponent(uri.replace('bitcoin:?r=', '')); - this.setFromPayPro(uri, function(err) { - if (err) { - return err; - } - }); - } else { - uri = sanitizeUri(uri); - - if (!bitcore.URI.isValid(uri)) { - return uri; - } - var parsed = new bitcore.URI(uri); - - var addr = parsed.address ? parsed.address.toString() : ''; - var message = parsed.message; - - var amount = parsed.amount ? - (parsed.amount.toFixed(0) * satToUnit).toFixed(this.unitDecimals) : 0; - - - if (parsed.r) { - this.setFromPayPro(parsed.r, function(err) { - if (err && addr && amount) { - self.setForm(addr, amount, message); - return addr; - } - }); - } else { - this.setForm(addr, amount, message); - return addr; - } - } - - }; - - this.onAddressChange = function(value) { - this.resetError(); - if (!value) return ''; - - if (this._paypro) - return value; - - if (value.indexOf('bitcoin:') === 0) { - return this.setFromUri(value); - } else if (/^https?:\/\//.test(value)) { - return this.setFromPayPro(value); - } else { - return value; - } - }; - - // History - - function strip(number) { - return (parseFloat(number.toPrecision(12))); - } - - this.getUnitName = function() { - return this.unitName; - }; - - this.getAlternativeIsoCode = function() { - return this.alternativeIsoCode; - }; - - this.openTxModal = function(btx) { - var self = this; - - $scope.btx = lodash.cloneDeep(btx); - $scope.self = self; - - $ionicModal.fromTemplateUrl('views/modals/tx-details.html', { - scope: $scope, - hideDelay: 500 - }).then(function(modal) { - $scope.txDetailsModal = modal; - $scope.txDetailsModal.show(); - }); - }; - - this.hasAction = function(actions, action) { - return actions.hasOwnProperty('create'); - }; - - this.sendMax = function(availableBalanceSat) { - if (availableBalanceSat == 0) { - this.error = gettext("Cannot create transaction. Insufficient funds"); - return; - } - - var self = this; - var fc = profileService.focusedClient; - this.error = null; - ongoingProcess.set('calculatingFee', true); - - feeService.getCurrentFeeValue(function(err, feePerKb) { - ongoingProcess.set('calculatingFee', false); - if (err || !lodash.isNumber(feePerKb)) { - self.error = gettext('Could not get fee value'); - return; - } - - var opts = {}; - opts.feePerKb = feePerKb; - opts.returnInputs = true; - var config = configService.getSync(); - opts.excludeUnconfirmedUtxos = !config.wallet.spendUnconfirmed; - ongoingProcess.set('retrivingInputs', true); - - fc.getSendMaxInfo(opts, function(err, resp) { - ongoingProcess.set('retrivingInputs', false); - - if (err) { - self.error = err; - $scope.$apply(); - return; - } - - if (resp.amount == 0) { - self.error = gettext("Not enough funds for fee"); - $scope.$apply(); - return; - } - - var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees", { - fee: profileService.formatAmount(resp.fee) + ' ' + self.unitName - }); - - var warningMsg = verifyExcludedUtxos(); - - if (!lodash.isEmpty(warningMsg)) - msg += '. \n' + warningMsg; - - confirmDialog.show(msg, function(confirmed) { - if (confirmed) { - self.sendMaxInfo = resp; - var amount = parseFloat((resp.amount * self.satToUnit).toFixed(self.unitDecimals)); - self.setForm(null, amount, null); - } else { - self.resetForm(); - } - }); - - function verifyExcludedUtxos() { - var warningMsg = []; - if (resp.utxosBelowFee > 0) { - warningMsg.push(gettextCatalog.getString("Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.", { - amountBelowFeeStr: profileService.formatAmount(resp.amountBelowFee) + ' ' + self.unitName - })); - } - if (resp.utxosAboveMaxSize > 0) { - warningMsg.push(gettextCatalog.getString("Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded", { - amountAboveMaxSizeStr: profileService.formatAmount(resp.amountAboveMaxSize) + ' ' + self.unitName - })); - } - return warningMsg.join('\n'); - } - }); - }); - }; - - /* Start setup */ - lodash.assign(self, vanillaScope); - - this.bindTouchDown(); - if (profileService.focusedClient) { - this.setAddress(); - this.setSendFormInputs(); - } - -}); - -angular.module('copayApp').run(['gettextCatalog', function (gettextCatalog) { -/* jshint -W100 */ - gettextCatalog.setStrings('cs', {"(possible double spend)":"(pravděpodobná dvojitá platba)","(Trusted)":"(Věrohodný)","[Balance Hidden]":"[skrytý zůstatek]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} bude odečteno jako poplatek bitcoinové síti","{{feeRateStr}} of the transaction":"{{feeRateStr}} z transakce","{{index.m}}-of-{{index.n}}":"{{index.m}} z {{index.n}}","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} transakce stažena","{{item.m}}-of-{{item.n}}":"{{item.m}} z {{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Návrh k platbě může být odstraněn pokud 1) jste jej vytvořil(a) a žádný spoluplátce jej nepodepsal 2) Uběhlo 24 hodin od vytvoření návrhu.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"POKUD ZTRATÍTE PŘÍSTUP K VAŠI SPOLUPLÁTCOVSKÉ PENĚŽENCE NEBO VAŠÍM ŠIFROVANÝM KLÍČŮM A NEMÁTE ULOŽENOU ZÁLOHU VAŠI PENĚŽENKY A HESLEM ZVLÁŠTĚ, BERETE NA VĚDOMÍ ŽE VŠECHNY BITCOINY ULOŽENÉ V TÉTO SPOLUPLÁTCOVSKÉ PENĚŽENCE NEBUDOU DOSTUPNÉ. ","A multisignature bitcoin wallet":"A vícepodpisová bitcoin peněženka","About Copay":"O Copay","Accept":"Přijmout","Account":"Účet","Account Number":"Číslo účtu","Activity":"Aktivita","Add a new entry":"Přidat nový záznam","Add wallet":"Přidat peněženku","Address":"Adresa","Address Type":"Typ adresy","Advanced":"Pokročilé","Alias":"Název","Alias for {{index.walletName}}":"Název pro {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Všichni spoluúčastníci překladů Copay jsou vítání. Přihlaště se na crowdin.com a přidejte se k projektu Copay na","All transaction requests are irreversible.":"Všechny žádosti o platbu jsou nevratné.","Alternative Currency":"Alternativní měna","Amount":"Částka","Amount in":"Částka v","Are you sure you want to delete this wallet?":"Opravdu si přejete odstranit tuto peněženku?","Available Balance":"Dostupný zůstatek","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Průměrný čas potvrzení je: {{fee.nbBlocks * 10}} minut","Back":"Zpět","Backup":"Záloha","Backup failed":"Chyba zálohování","Backup Needed":"Vyžadována záloha","Backup now":"Vytvořit zálohu","Bad wallet invitation":"Chybný požadavek do peněženky","Balance By Address":"Zůstatek adres","BIP32 path for address derivation":"BIP32 cesta pro derivaci adres","Bitcoin address":"Bitcoin adresa","Bitcoin Network Fee Policy":"Zásady poplatků bitcoinové sítě","Bitcoin URI is NOT valid!":"Bitcoin URI neni platná!","Broadcast Payment":"Vysílání platby","Broadcasting transaction":"Vysílání transakce","Browser unsupported":"Nepodporovaný prohlížeč","Calculating fee":"Vypočítávám poplatek","Cancel":"Zrušit","Cancel and delete the wallet":"Zrušit a odstranit peněženku","Cannot create transaction. Insufficient funds":"Nelze vytvořit transakci. Nedostatek prostředků","Cannot join the same wallet more that once":"Nelze spojit stejnou peněženku více než jednou","Cannot sign: The payment request has expired":"Chyba podpisu: Návrh platby vypršel","Certified by":"Ověřeno od","Changing wallet alias only affects the local wallet name.":"Změna názvu peněženky bude aktualizovat pouze název na tomto zařízení.","Choose a backup file from your computer":"Vyberte zálohu z PC","Clear cache":"Vymazat cache","Close":"Zavřít","Color":"Barva","Commit hash":"Hash softwaru","Confirm":"Potvrdit","Confirmations":"Potvrzení","Congratulations!":"Gratulujeme!","Connection reset by peer":"Spojení obnoveno uzlem","Continue":"Pokračovat","Copayer already in this wallet":"Spoluplátce je již v peněžence","Copayer already voted on this spend proposal":"Spoluplátce pro tento návrh již hlasoval","Copayer data mismatch":"Data spoluplátce nesouhlasí","Copayers":"Spoluplátci","Copied to clipboard":"Zkopírováno","Copy this text as it is to a safe place (notepad or email)":"Zkopírujte tento text do bezpečného místa (např. email nebo poznámkový blok)","Copy to clipboard":"Zkopírovat","Could not access Wallet Service: Not found":"Nebylo možné navázat spojení se službou peněženky: Nebyla nalezena","Could not broadcast payment":"Nebylo možné vyslat platbu","Could not build transaction":"Nebylo možné sestavit transakci","Could not create address":"Nebylo možné vytvořit adresu","Could not create payment proposal":"Nebylo možné vytvořit návrh platby","Could not create using the specified extended private key":"Nebylo možné vytvořit rozšířený veřejný klíč","Could not create using the specified extended public key":"Nebylo možné vytvořit rozšířený veřejný klíč","Could not delete payment proposal":"Nepodařilo se odstranit návrh platby","Could not fetch payment information":"Nebylo možné získat údaje platby","Could not get fee value":"Nebylo možné získat hodnotu poplatku","Could not import":"Chyba importu","Could not join wallet":"Chyba spojování peněženek","Could not recognize a valid Bitcoin QR Code":"Bitcoin QR kód nebyl rozpoznán","Could not reject payment":"Chyba odmítnutí platby","Could not send payment":"Chyba při odesílání platby","Could not update Wallet":"Chyba při aktualizování platby","Create":"Vytvořit","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Vytvořit peněženku {{requiredCopayers}}-z-{{totalCopayers}}","Create new wallet":"Vytvořit novou peněženku","Create, join or import":"Vytvořit, spojit nebo importovat","Created by":"Vytvořil","Creating transaction":"Vytvářím transakci","Creating Wallet...":"Vytvářím peněženku...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Současná zásadu poplatků je: {{fee.feePerKBUnit}}/kiB","Date":"Datum","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Dešifrování papírové peněženky může na tomto zařízení trvat okolo 5 minut, buďte prosím trpělivý a nechejte aplikaci otevřenou.","Delete it and create a new one":"Smazat a vytvořit novou","Delete Payment Proposal":"Odstranit návrh platby","Delete wallet":"Odstranit peněženku","Delete Wallet":"Odstranit peněženku","Deleting Wallet...":"Mažu peněženku...","Derivation Path":"Cesta derivace","Derivation Strategy":"Způsob derivace","Details":"Detail","Disabled":"Nedostupné","Do not include private key":"Nevyplňujte soukromý klíč","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Nevidíte na Crowdin váš jazyk? Kontaktujte správce repozitáře na Crowdin. Rádi váš jazyk přidáme.","Done":"Hotovo","Download":"Stáhnout","Economy":"Ekonomický","Edit":"Upravit","Email for wallet notifications":"Email pro upozornění","Email Notifications":"Email upozornění","Empty addresses limit reached. New addresses cannot be generated.":"Limit prázdných adres dovrše. Nové adresy nemohou být vytvořeny.","Enable push notifications":"Povolit notifikace","Encrypted export file saved":"Šifrovaný soubor byl vytvořen","Enter your password":"Vyplňte heslo","Error at Wallet Service":"Chyba Služby Peněženky","Error creating wallet":"Chyba vytváření peněženky","Expired":"Vyprošelo","Expires":"Vyprší","Export options":"Možnosti exportu","Export to file":"Exportovat do souboru","Export Wallet":"Exportovat peněženku","Extended Public Keys":"Rozšířený veřejný klíč","Failed to export":"Chyba exportu","Failed to verify backup. Please check your information":"Chyba ověření zálohy. Zkontrolujte zadané informace","Family vacation funds":"Úspory rodiny na dovolenou","Fee":"Poplatek","Fetching Payment Information":"Stahuji platební údaje","Finish":"Konec","French":"Francouzština","Funds are locked by pending spend proposals":"Zůstatky jsou blokovány probíhajícím návrhem platby","Funds found":"Zůstatky nalezeny","Funds received":"Obdržena platba","Funds will be transferred to":"Částka bude převedena k","Generate new address":"Vytvořit novou adresu","Generate QR Code":"Vytvořit QR kód","Generating .csv file...":"Vytvářím .csv soubor...","German":"Němčina","Getting address for wallet {{selectedWalletName}} ...":"Získávání adres peněženky {{selectedWalletName}} ...","Global preferences":"Obecná nastavení","Hardware wallet":"Hardware peněženka","Hardware Wallet":"Hardwarová peněženka","Hide advanced options":"Skrýt rozšířená nastavení","I affirm that I have read, understood, and agree with these terms.":"Potvrzuji, že jsem si přečetl, porozuměl a odsouhlasil uvedené podmínky.","I AGREE. GET STARTED":"SOUHLASÍM. ZAČÍT","Import":"Import","Import backup":"Import zálohy","Import wallet":"Import peněženky","Importing Wallet...":"Importuji peněženku...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"Za žádných okolností autoři softwaru, zaměstnanci a přidružené osoby z Bitpay, vlastníci ochranných známek, BitPay, Inc nejsou odpovědni za škody nebo náhradu nákladů, plynoucí z používání tohoto softwaru.","Incorrect address network":"Neplatná síť adres","Insufficient funds":"Nedostatečná částka","Insufficient funds for fee":"Nedostatečný zůstatek pro poplatek","Invalid":"Neplatné","Invalid account number":"Neplatné číslo účtu","Invalid address":"Neplatná adresa","Invalid derivation path":"Neplatná cesta derivace","Invitation to share a Copay Wallet":"Pozvánka ke sdílené Copay Peněžence","Japanese":"Japonština","John":"John","Join":"Spojit","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Propojení mé Copay peněženky. Toto je kód pozvánky: {{secret}} Copay je možné stáhnout do telefonu nebo počítače na https://copay.io","Join shared wallet":"Spojit sdílenou peněženku","Joining Wallet...":"Spojuji peněženky...","Key already associated with an existing wallet":"Klíč je již spojený s některou z peněženek","Label":"Štítek","Language":"Jazyk","Last Wallet Addresses":"Poslední adresa peněženky","Learn more about Copay backups":"Dozvědět se více o zálohování Copay","Loading...":"Načítám...","locked by pending payments":"zablokováno probíhající platbou","Locktime in effect. Please wait to create a new spend proposal":"Čekání na locktime. Prosím vyčkejte na vytvoření nového platebního návrhu","Locktime in effect. Please wait to remove this spend proposal":"Čekání na locktime. Prosím vyčkejte na vytvoření tohoto platebního návrhu","Make a payment to":"Vytvořit platbu pro","Matches:":"Shody:","me":"já","Me":"Já","Memo":"Poznámka","Merchant message":"Zpráva obchodníka","Message":"Zpráva","Missing private keys to sign":"Chybějící soukromý klíč pro podpis","Moved":"Přesunuto","Multiple recipients":"Více příjemců","My Bitcoin address":"Moje bitcoin adresa","My contacts":"Moje kontakty","My wallets":"Moje peněženky","Need to do backup":"Vyžaduje zálohu","Network":"Síť","Network connection error":"Chyba síťového spojení","New Payment Proposal":"Nový návrh platby","No hardware wallets supported on this device":"Toto zařízení nejsou podporována žádná hardware zařízení","No transactions yet":"Žádné transakce","Normal":"Normální","Not authorized":"Neautorizováno","Not completed":"Nedokončeno","Not valid":"Neplatné","Note":"Poznámka","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Poznámka: celkem {{amountAboveMaxSizeStr}} bylo vyloučeno. Byla překročena maximální povolená velikost transakce","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Pozn.: bylo vyloučeno celkem {{amountBelowFeeStr}}. Tyto prostředky pocházejí z menších UTXO, než kolik činí poplatek sítě.","Official English Disclaimer":"Oficiální Disclaimer v Angličtině","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Viditelné jsou pouze hlavní (ne adresy pro vratky). Adresy na tomto seznamu nebyly lokálně ověřeny.","Open Settings app":"Otevřít nastavení aplikace","optional":"nepovinný","Paper Wallet Private Key":"Soukromý klíč papírové peněženky","Participants":"Účastníci","Passphrase":"Heslo","Password":"Heslo","Paste invitation here":"Pozvánku zkopírujte sem","Paste the backup plain text code":"Zálohu zkopírujte sem","Paste your paper wallet private key here":"Soukromý klíč papírové peněženky zkopírujte sem","Pasted from clipboard":"Zkopírovano","Pay To":"Placeno komu","Payment Accepted":"Platba přijata","Payment accepted, but not yet broadcasted":"Platba přijata, ale doposud nebyla odeslána","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Platba přijata. Bude vyslánat do sítě pomocí Glidera. V případě, že nastanou komplikace, může být odstraněna po 6 hodinách od vytvoření.","Payment details":"Údaje platby","Payment expires":"Expirace platby","Payment Proposal":"Návrh platby","Payment Proposal Created":"Návrh platby byl vytvořen","Payment Proposal Rejected":"Návrh platby byl odmítnut","Payment Proposal Rejected by Copayer":"Návrh platby odmítnut spoluplátcem","Payment Proposal Signed by Copayer":"Návrh platby byl podepsán spoluplátcem","Payment Proposals":"Návrhy plateb","Payment Protocol Invalid":"Neplatný platební protokol","Payment Protocol not supported on Chrome App":"Chrome App nepodporuje Platební protokol","Payment Rejected":"Platba odmítnuta","Payment request":"Žádost platby","Payment Sent":"Platba odeslána","Payment to":"Platba komu","Pending Confirmation":"Vyčkávající potvrzení","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Trvalé odstraněné této peněženky. NELZE VRÁTIT ZPĚT","Personal Wallet":"Osobní peněženka","Please enter the required fields":"Vyplňte požadovaná pole","Please tap the words in order to confirm your backup phrase is correctly written.":"Potvrďte pořadí slov pro potvrzení správnosti zálohy.","Please upgrade Copay to perform this action":"Pro tuto funkci je potřeba aktualizovat Copay","Please, select your backup file":"Vyberte soubor zálohy","Preparing backup...":"Připravuji zálohu...","Press again to exit":"Pro ukončení stiskněte tlačítko znovu","Priority":"Priorita","Private key is encrypted, cannot sign":"Soukromý klíč je šifrovaný, nelze podepsat","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Oznámení pro Copay jsou v současné době zakázána. Povolte v nastavení aplikace.","QR Code":"QR kód","QR-Scanner":"QR čtečka","Receive":"Přijmout","Received":"Přijato","Recipients":"Příjemci","Recreate":"Znovu vytvářím","Recreating Wallet...":"Znovu vytvářím peněženku...","Reject":"Odmítnout","Release Information":"Vypouštění informací","Remove":"Odstranit","Repeat password":"Heslo znovu","Request a specific amount":"Vyžádat konkrétní částku","Required":"Vyžadováno","Required number of signatures":"Vyžadováno více podpisuů","Retrieving inputs information":"Načítání informací vstupů","Russian":"Ruština","Save":"Uložit","Scan addresses for funds":"Naskenujte adresu pro zobrazení zůstatku","Scan Fingerprint":"Skenovat otisk","Scan Finished":"Skenování dokončeno","Scan status finished with error":"Status skenování je chybová","Scan Wallet Funds":"Skenovat zůstatek peněženky","Scan your fingerprint please":"Naskenujte prosím svůj otisk","Scanning Wallet funds...":"Skenuji zůstatek peněženky...","Search transactions":"Vyhledávám transakce","Security preferences":"Nastavení zabezpečení","See it on the blockchain":"Zobrazit na blockchainu","Select a backup file":"Vybrat soubor zálohy","Select a wallet":"Vybrat peněženku","Self-signed Certificate":"Vlastnoručně podepsaný certifikát","Send":"Odesláno","Send addresses by email":"Odeslat adresy emailem","Send bitcoin":"Odeslat BTC","Send by email":"Odeslat emailem","Send Max":"Odeslat max","Sending":"Odesílám","Sending transaction":"Odesílání transakce","Sent":"Odesláno","Server response could not be verified":"Server nemůže být ověřen","Session log":"Log sekce","SET":"NASTAVIT","Set default url":"Nastavit výchozí URL","Set up a password":"Nastavit heslo","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Nastavení emailových notifikací může snížit vaše soukromí, pokud je poskytovatel emailu napaden. Útočník by mohl mít k dispozici vaše adresy peněženek a zůstatek, soukromé klíče k ovládání zůstatků ne.","Settings":"Nastavení","Share address":"Sdílet adresu","Share invitation":"Sdílet pozvánku","Share this invitation with your copayers":"Sdílet tuto pozvánku se spoluplátci","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Sdílet adresu této peněženky pro přijímání plateb. Pro ochranu soukromí po použití adresy je generována nová.","Shared Wallet":"Sdílená peněženka","Show advanced options":"Zobrazit rozšířená nastavení","Signatures rejected by server":"Podpisy byly serverem odmítnuty","Spanish":"Španělština","Spend proposal is not accepted":"Návrh platby nebyl přijat","Spend proposal not found":"Návrh platby nebyl nalezen","Success":"Úspěšné","Sweep paper wallet":"Převést papírovou peněženku","Sweep Wallet":"Převést peněženku","Tap to retry":"Klikněte pro zopakování pokusu","Terms of Use":"Podmínky používání","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Autoři tohoto software, zaměstnanci a ostatní z Bitpay, vlastníci ochranných známek, BitPay, Inc, nemůže obnovit vaše soukromé klíče nebo hesla, pokud dojde ke ztrátě a negarantuje potvrzení transakcí, protože nedrží kontrolu nad Bitcoin sítí.","The Ledger Chrome application is not installed":"Chrome aplikace pro Leger není instalována","The payment was created but could not be completed. Please try again from home screen":"Platba byla vytvořena ale nemohla být dokončena. Opakujte akci z domovské obrazovky","The payment was removed by creator":"Platba byla odstraněna tvůrcem","The request could not be understood by the server":"Požadavek nebyl serverem pochopen","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Tento software nepředstavuje účet kde BitPay nebo jiné třetí strany slouží jako finanční zprostředkovatelé nebo správci vašeho bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Software který hodláte začít používat je zdarma, open-source, vícepodpisová digitální peněženka.","The spend proposal is not pending":"Platební návrh neočekává další schválení","The wallet \"{{walletName}}\" was deleted":"Peněženka \"{{walletName}}\" byla odstraněna","There are no wallets to make this payment":"Pro platbu je potřeba založit peněženku","There is a new version of Copay. Please update":"Existuje nová verze Copay. Proveďte aktualizaci","There is an error in the form":"Na formuláři je chyba","This transaction has become invalid; possibly due to a double spend attempt.":"Transakce je neplatná, zřejmě kvůli pokusu o dvojí platbu.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Tato peněženka není registrována na Bitcore Wallet Service (BWS). Můžete jej znovu vytvořit z lokální informací.","Time":"Čas","To":"Komu","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Pro obnovu této {{index.m}} z {{index.n}} sdílené peněženky potřebujete","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"V plném rozsahu povoleném zákonem tento software je poskytován \"tak jak je\" a žádné prohlášení ani záruky nemohou být zaručeny.","too long!":"příliš dlouho!","Total Locked Balance":"Blokovaný zůstatek","Total number of copayers":"Počet spoluplátců","Touch ID Failed":"Chyba Touch ID","Transaction":"Transakce","Transaction already broadcasted":"Transakce byla již odeslána","Transaction History":"Historie transakcí","Translation Credits":"Poděkování překladatelům","Translators":"Překladatelé","Try again":"Zkusit znovu","Unconfirmed":"Nepotvrzené","Unit":"Jednotka","Unsent transactions":"Neodeslaná transakce","Updating transaction history. Please stand by.":"Aktualizuji historii transakcí.","Updating Wallet...":"Aktualizuji peněženku...","Use Unconfirmed Funds":"Použít nepotvrzené částky","Version":"Verze","View":"Pohled","Waiting for copayers":"Vyčkávání na spoluplátce","Waiting...":"Vyčkávání...","Wallet already exists":"Peněženka již existuje","Wallet Configuration (m-n)":"Nastavení peněženky (m z n)","Wallet Export":"Export peněženky","Wallet Id":"Id peněženky","Wallet incomplete and broken":"Peněženka je neúplná a chybná","Wallet Information":"Údaje peněženky","Wallet Invitation":"Pozvánka peněženky","Wallet Invitation is not valid!":"Neplatná pozvánka peněženky!","Wallet is full":"Peněženka je plná","Wallet is locked":"Peněženka je zablokována","Wallet is not complete":"Peněženka není úplná","Wallet name":"Název peněženky","Wallet Name (at creation)":"Název peněženky (při vytváření)","Wallet Network":"Síť peněženky","Wallet not found":"Peněženka nenalezena","Wallet service not found":"Služba peněženky nenalezena","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"VAROVÁNÍ: Bez vložení soukromého klíče je možná kontrola zůstatků peněženek, historie transakcí a vytváření návrhů plateb z exportu. Nicméně, tyto údaje neumožňují (podepsat) návrhy plateb, tudíž zůstatky nebudou z exportů ovladatelné.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"VAROVÁNÍ: Soukromý klíč této peněženky není dostupný. Export umožňuje kontrolu zůstatků peněženky, historii transakcí, vytvoření návrhu platby z exportu. Nicméně neumožňuje potvrdit (podepsat) návrhy, zůstatky budou z exportu neovladatelné.","Warning: this transaction has unconfirmed inputs":"Varování: Tato transakce odesílá nepotvrzené zůstatky","WARNING: UNTRUSTED CERTIFICATE":"VAROVÁNÍ: NEDŮVĚRYHODNÝ CERTIFIKÁT","WARNING: Wallet not registered":"VÁROVÁNÍ: Neregistrovaná peněženka","Warning!":"Varování!","We reserve the right to modify this disclaimer from time to time.":"Rezervujeme si právu upravit podmínky užívání.","WELCOME TO COPAY":"VÍTEJTE V COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Zatímco software byl podroben testování beta a nadále je vylepšován zpětnou vazbou od open source uživatelské a vývojářské komunity, nemůžeme zaručit, že nedojde k žádným chybám v softwaru.","Yes":"Ano","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Potvrzujete, že používáte tento software na vlastní uvážení a v souladu se všemi platnými zákony.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Jste odpovědni za bezpečné uchování hesel, soukromých klíčů, PINů a další údajů potřebných pro ovládání softwaru.","You assume any and all risks associated with the use of the software.":"Berete na vědomí risk spojený s používání tohoto softwaru.","You backed up your wallet. You can now restore this wallet at any time.":"Zálohovali jste peněženku. Nyní je možné přistoupit k obnově.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Bezpečně můžete instalovat peněženku na jiné zařízení a použít jej z jiného zařízení ve stejnou dobu.","Your nickname":"Vaše přezdívka","Your password":"Vaše heslo","Your wallet has been imported correctly":"Vaše peněženka byla úspěšně importována"}); - gettextCatalog.setStrings('de', {"(possible double spend)":"(mögliche Doppelausgabe)","(Trusted)":"(Vertraut)","[Balance Hidden]":"[Guthaben versteckt]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} wird als Netzwerkgebühr abgezogen","{{feeRateStr}} of the transaction":"{{feeRateStr}} der Transaktion","{{index.m}}-of-{{index.n}}":"{{index.m}}-von-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} weitere","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} Transaktionen werden heruntergeladen","{{item.m}}-of-{{item.n}}":"{{item.m}}-von-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Ein Zahlungsvorschlag kann gelöscht werden, wenn 1) Du diesen erzeugt hast und noch kein anderer Copayer unterschrieben hat, oder 2) 24 Stunden vergangen sind, seit der Vorschlag erstellt wurde.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"WENN DER ZUGRIFF AUF DAS COPAY WALLET ODER DEN VERSCHLÜSSELTEN PRIVATEN SCHLÜSSELN VERLOREN GEHT UND KEINE SICHERUNG DES WALLETS UND KORRESPONDIERENDEM PASSWORT EXISTIERT, DANN WIRD BESTÄTIGT UND AKZEPTIERT, DASS AUF ALLE MIT DIESEM WALLET VERBUNDENEN BITCOIN KEIN ZUGRIFF MEHR MÖGLICH IST.","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"ODER 1 Exportdatei des Wallets und und die noch benötigten Wallet-Wiederherstellungsphrasen (z.B. für ein 3-5 Wallet: 1 Exportdatei + 2 Wallet-Wiederherstellungsphrasen anderer Copayer).","OR the wallet recovery phrase of all copayers in the wallet":"ODER die Wallet-Wiederherstellungsphrasen aller Copayer des Wallets","OR the wallet recovery phrases of all copayers in the wallet":"ODER die Wallet-Wiederherstellungsphrasen aller Copayer des Wallets","A multisignature bitcoin wallet":"Ein Bitcoin Wallet mit Mehrfachunterschriften","About Copay":"Über Copay","Accept":"Akzeptieren","Account":"Benutzerkonto","Account Number":"Kontonummer","Activity":"Aktivität","Add a new entry":"Einen neuen Eintrag hinzufügen","Add a Password":"Passwort festlegen","Add an optional password to secure the recovery phrase":"Ein optionales Passwort zur Sicherung der Wiederherstellungsphrase hinzufügen","Add comment":"Kommentar hinzufügen","Add wallet":"Wallet hinzufügen","Address":"Adresse","Address Type":"Adresstyp","Advanced":"Erweitert","Alias":"Alias","Alias for {{index.walletName}}":"Alias für {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Alle Beiträge zur Übersetzung von Copay sind willkommen. Melde Dich bei crowdin.com an verbinde Dich mit dem Copay-Projekt über","All transaction requests are irreversible.":"Transaktionen können unmöglich rückgängig gemacht werden.","Alternative Currency":"Alternative Währung","Amount":"Betrag","Amount below minimum allowed":"Betrag unter zulässigem Minimum","Amount in":"Betrag in","Are you sure you want to delete the recovery phrase?":"Sind Sie sicher, dass Sie die Wiederherstellungsphrase löschen möchten?","Are you sure you want to delete this wallet?":"Soll das Wallet wirklich gelöscht werden?","Auditable":"Prüffähig","Available Balance":"Verfügbarer Gesamtbetrag","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Durchschnittliche Zeit für die Bestätigung der Transaktion: {{fee.nbBlocks * 10}} Minuten","Back":"Zurück","Backup":"Sicherung","Backup failed":"Backup ist fehlgeschlagen","Backup Needed":"Backup wird benötigt","Backup now":"Jetzt sichern","Bad wallet invitation":"Ungültige Einladung","Balance By Address":"Guthaben nach Adresse","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Es ist notwendig Ihre Brieftasche zu sichern bevor Sie Beträge empfangen. Wenn Sie dieses Gerät verlieren, ist es ohne Sicherung unmöglich auf empfangene Beträge zuzugreifen.","BETA: Android Key Derivation Test:":"BETA: Android Key Derivation Test:","BIP32 path for address derivation":"BIP32 Pfad für die Adressen-Ableitung","Bitcoin address":"Bitcoinadresse","Bitcoin Network Fee Policy":"Bitcoin-Netzwerk Gebührenübersicht","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Für Bitcoin-Transaktionen können Gebühren hinzugefügt werden. Transaktionen mit höheren Gebühren werden meist schneller verarbeitet und bestätigt. Die tatsächlichen Gebühren werden anhand der Netzwerklast und der ausgewählte Richtlinie bestimmt.","Bitcoin URI is NOT valid!":"Bitcoin URI ist NICHT gültig!","Broadcast Payment":"Zahlung übermitteln","Broadcasting transaction":"Übermittlung der Transaktion","Browser unsupported":"Der eingesetzte Browser wird nicht unterstützt","Calculating fee":"Mining-Fee Berechnung","Cancel":"Abbruch","Cancel and delete the wallet":"Abbrechen und Brieftasche löschen","Cannot create transaction. Insufficient funds":"Transaktion kann nicht erstellt werden. Keine Deckung","Cannot join the same wallet more that once":"An einem Wallet kann nicht mehrfach teilgenommen werden","Cannot sign: The payment request has expired":"Signieren nicht möglich: die Zahlungsanforderung ist abgelaufen","Certified by":"Zertifiziert von","Changing wallet alias only affects the local wallet name.":"Änderung der Aliases hat nur Auswirkungen auf den lokalen Namen des Wallets","Chinese":"Chinesisch","Choose a backup file from your computer":"Bitte eine Sicherungsdatei vom Computer wählen","Clear cache":"Cache leeren","Close":"Schließen","Color":"Farbe","Comment":"Kommentar","Commit hash":"Hash übertragen","Confirm":"Bestätigen","Confirm your wallet recovery phrase":"Bestätigen Sie Ihre Wallet-Wiederherstellungsphrase","Confirmations":"Bestätigungen","Congratulations!":"Herzlichen Glückwunsch!","Connecting to Coinbase...":"Verbinde mit Coinbase...","Connecting to Glidera...":"Verbinde mit Glidera...","Connection reset by peer":"Verbindung von Peer zurückgesetzt","Continue":"Weiter","Copayer already in this wallet":"Copayer nimmt bereits teil","Copayer already voted on this spend proposal":"Copayer hat schon für diesen Zahlungsvorschlag angestimmt","Copayer data mismatch":"Copayer Datenkonflikt","Copayers":"Copayer","Copied to clipboard":"In die Zwischenablage kopiert","Copy this text as it is to a safe place (notepad or email)":"Diesen Text an einem sichern Ort einfügen (Notepad oder E-Mail)","Copy to clipboard":"In die Zwischenablage kopieren","Could not access the wallet at the server. Please check:":"Kein Zugriff auf Wallet des Servers. Überprüfen Sie bitte:","Could not access wallet":"Auf Wallet konnte nicht zugegriffen werden","Could not access Wallet Service: Not found":"Auf den Wallet-Dienst konnte nicht zugegriffen werden: Nicht gefunden","Could not broadcast payment":"Zahlung konnte nicht gesendet werden","Could not build transaction":"Transaktion konnte nicht erstellt werden","Could not create address":"Adresse konnte nicht erstellt werden","Could not create payment proposal":"Es kann kein Zahlungsvorschlag erzeugt werden","Could not create using the specified extended private key":"Erzeugung mit erweiterten privaten Schlüssel nicht möglich","Could not create using the specified extended public key":"Erzeugung mit dem angegebenen erweiterten öffentlichen Schlüssel nicht möglich","Could not create: Invalid wallet recovery phrase":"Wallet-Wiederherstellungsphrase nicht gültig","Could not decrypt file, check your password":"Datei konnte nicht entschlüsselt werden, bitte das Passwort überprüfen","Could not delete payment proposal":"Zahlungsvorschlag konnte nicht gelöscht werden","Could not fetch payment information":"Zahlungsinformationen können nicht abgerufen werden","Could not get fee value":"Gebühr konnte nicht ermittelt werden","Could not import":"Import nicht möglich","Could not import. Check input file and spending password":"Import nicht möglich. Bitte Datei und Berechtigungscode überprüfen","Could not join wallet":"Beteiligung am Wallet nicht möglich","Could not recognize a valid Bitcoin QR Code":"Es konnte kein gültiger Bitcoin-QR-Code erkannt werden","Could not reject payment":"Zahlung konnte nicht abgelehnt werden","Could not send payment":"Zahlung kann nicht gesendet werden","Could not update Wallet":"Wallet kann nicht aktualisiert werden","Create":"Erzeugen","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Ein {{requiredCopayers}}-von-{{totalCopayers}} Wallet erzeugen","Create new wallet":"Neues Wallet erzeugen","Create, join or import":"NEU | TEILNAHME | IMPORT","Created by":"Erstellt von","Creating transaction":"Transaktion erstellen","Creating Wallet...":"Wallet erstellen...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Aktuelle Gebühr für dieses Einstellung: {{fee.feePerKBUnit}}/KiB","Czech":"Tschechisch","Date":"Datum","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Das Entschlüsseln eines Paperwallets kann auf diesem Gerät bis zu 5 Minuten dauern. Bitte abwarten und die App nicht beenden.","Delete it and create a new one":"Löschen und neues Wallet erzeugen","Delete Payment Proposal":"Zahlungsvorschlag löschen","Delete recovery phrase":"Wiederherstellungsphrase löschen","Delete Recovery Phrase":"Wiederherstellungsphrase löschen","Delete wallet":"Wallet löschen","Delete Wallet":"Wallet löschen","Deleting Wallet...":"Wallet wird gelöscht...","Derivation Path":"Ableitungsstruktur","Derivation Strategy":"Ableitungstrategie","Description":"Beschreibung","Details":"Details","Disabled":"Deaktiviert","Do not include private key":"Den privaten Schlüssel nicht einbeziehen","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Wird deine Sprache auf Crowdin nicht angezeigt? Kontaktiere den Support von Crowdin, denn wir würden deine Sprache gerne hinzufügen.","Done":"Fertig","Download":"Herunterladen","Economy":"Wirtschaftlich","Edit":"Bearbeiten","Edit comment":"Kommentar bearbeiten","Edited by":"Editiert von","Email for wallet notifications":"E-Mail für Wallet Benachrichtigungen","Email Notifications":"Benachrichtigunen per E-Mail","Empty addresses limit reached. New addresses cannot be generated.":"Obergrenze für leere Adressen erreicht. Neue Adressen können nicht generiert werden.","Enable Coinbase Service":"Coinbase-Dienst aktivieren","Enable Glidera Service":"Glidera-Dienst aktivieren","Enable push notifications":"Pushbenachrichtigungen aktivieren","Encrypted export file saved":"Verschlüsselte Exportdatei gespeichert","Enter the recovery phrase (BIP39)":"Wiederherstellungsphrase eingeben (BIP39)","Enter your password":"Passwort eingeben","Enter your spending password":"Berechtigungscode eingeben","Error at Wallet Service":"Fehler beim Wallet-Dienst","Error creating wallet":"Fehler beim Erstellen des Wallets","Expired":"Abgelaufen","Expires":"Gültig bis","Export options":"Export-Optionen","Export to file":"In eine Datei exportieren","Export Wallet":"Wallet exportieren","Exporting via QR not supported for this wallet":"Für diese Wallet ist Export per QR nicht unterstützt","Extended Public Keys":"Erweiterte öffentliche Schlüssel","Extracting Wallet Information...":"Entpacke Wallet...","Failed to export":"Fehler beim Exportieren","Failed to verify backup. Please check your information":"Die Überprüfung der Sicherung ist gescheitert. Bitte überprüfen Sie Ihre Angaben","Family vacation funds":"Familienurlaub","Fee":"Gebühr","Fetching Payment Information":"Zahlungsinformationen abrufen","File/Text":"Datei/Text","Finger Scan Failed":"Abtasten des Fingerabdrucks gescheitert","Finish":"Beenden","For audit purposes":"Zur Kontrolle","French":"Français","From the destination device, go to Add wallet > Import wallet and scan this QR code":"Gehen Sie auf Wallet Hinzufügen > Wallet Importieren von dem Zielgerät und scannen Sie diesen QR-Code","Funds are locked by pending spend proposals":"Beträge sind durch ausstehende Zahlungsvorschläge gesperrt","Funds found":"Beträge gefunden","Funds received":"Beträge empfangen","Funds will be transferred to":"Beträge werden überwiesen an","Generate new address":"Neue Adresse erzeugen","Generate QR Code":"QR-Code generieren","Generating .csv file...":"CSV-Datei erzeugen...","German":"Deutsch","Getting address for wallet {{selectedWalletName}} ...":"Ermittle die Adresse des Wallets {{selectedWalletName}}...","Global preferences":"Globale Einstellungen","Hardware wallet":"Hardware-Wallet","Hardware Wallet":"Hardware-Wallet","Hide advanced options":"Erweiterte Optionen ausblenden","I affirm that I have read, understood, and agree with these terms.":"Ich bestätige, dass ich diese Bedingungen gelesen habe, diese verstehe und diesen zustimme.","I AGREE. GET STARTED":"Ich stimme zu. Lege los!","Import":"Import","Import backup":"Importiere Sicherung","Import wallet":"Wallet importieren","Importing Wallet...":"Wallet wird importiert...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"Die Autoren der Software, Mitarbeiter und Partner von Bitpay, Inhaber von Urheberrechten oder Bitpay Inc., haften in keinem Fall für Schäden oder Ansprüche, die sich im Rahmen einer Klage zum Vertrag, unerlaubter Handlung, auf andere Weise oder aus bzw. im Zusammenhang mit der Software ergeben.","In order to verify your wallet backup, please type your password:":"Um die Sicherung der Wallet zu überprüfen, geben Sie bitte Ihr Passwort ein:","Incorrect address network":"Falsche Netzwerk-Adresse","Incorrect code format":"QR code hat falsches Format","Insufficient funds":"Nicht ausreichendes Guthaben","Insufficient funds for fee":"Nicht ausreichendes Guthaben für die Gebühr","Invalid":"Ungültig","Invalid account number":"Ungültige Kontonummer","Invalid address":"Ungültige Adresse","Invalid derivation path":"Ungültige Ableitungsstruktur","Invitation to share a Copay Wallet":"Einladung zum Copay-Wallet teilen","Italian":"Italienisch","Japanese":"日本語","John":"Sascha","Join":"Teilnehmen","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Copay Wallet beitreten. Hier ist der Einladungscode: {{secret}} Die Desktopversion oder die App fürs Handy kann auf https://copay.io heruntergeladen werden","Join shared wallet":"Gemeinschaftliches Wallet","Joining Wallet...":"Teilnahme am Wallet einrichten...","Key already associated with an existing wallet":"Schlüssel ist bereits mit einem existierenden Wallet verbunden","Label":"Beschreibung","Language":"Sprache","Last Wallet Addresses":"Letzte Wallet-Adressen","Learn more about Copay backups":"Erfahren Sie mehr über Copay-Sicherungen","Loading...":"Lade...","locked by pending payments":"durch ausstehende Zahlungen gesperrt","Locktime in effect. Please wait to create a new spend proposal":"Zeitsperre aktiv. Bitte mit neuem Zahlungsvorschlag warten","Locktime in effect. Please wait to remove this spend proposal":"Zeitsperre aktiv. Bitte auf die Entfernung des Zahlungsvorschlags warten","Make a payment to":"Sende eine Zahlung an","Matches:":"Übereinstimmungen:","me":"Ich","Me":"Ich","Memo":"Notiz","Merchant message":"Händlernachricht","Message":"Nachricht","Missing parameter":"Angabe fehlt","Missing private keys to sign":"Zum Signieren fehlen die privaten Schlüssel","Moved":"Verschoben","Multiple recipients":"Mehrere Empfänger","My Bitcoin address":"Eigene Bitcoinadresse","My contacts":"Meine Kontakte","My wallets":"Meine Wallets","Need to do backup":"Zuerst ist eine Sicherung notwendig","Network":"Netzwerk","Network connection error":"Netzwerkverbindungsfehler","New Payment Proposal":"Neue Zahlungsvorschlag","New Random Recovery Phrase":"Neue zufällige Wiederherstellungsphrase","No hardware wallets supported on this device":"Hardware-Wallets werden auf diesem Gerät nicht unterstützt","No transactions yet":"Noch keine Transaktionen","Normal":"Normal","Not authorized":"Nicht berechtigt","Not completed":"Nicht abgeschlossen","Not enough funds for fee":"Das Guthaben reicht nicht für die Gebühr","Not valid":"Nicht gültig","Note":"Notiz","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Hinweis: insgesamt wurden {{amountAboveMaxSizeStr}} ausgeschlossen. Die maximale Größe für eine Transaktion wurde überschritten","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Hinweis: insgesamt {{amountBelowFeeStr}} wurden ausgeschlossen. Diese Gelder stammen aus UTXOs, die kleiner sind als die Netzwerkgebühr.","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"Hinweis: Um eine Brieftasche aus einer 3rd-Party-Software zu importieren, gehen Sie bitte auf Wallet Hinzufügen > Wallet Importieren, und geben Sie die Wiederhestellungsphrase ein.","Official English Disclaimer":"Offizieller englischer Haftungsausschluss","OKAY":"Okay","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"Sobald Sie Ihre Wallet-Wiederherstellungsphrase kopiert haben, wird empfohlen, diese vom Gerät zu löschen.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Nur die Haupt (unveränderbaren) Adressen werden angezeigt. Die Adressen in dieser Liste sind momentan noch nicht lokal überprüft.","Open Settings app":"Einstellungen öffnen","optional":"zusätzlich","Paper Wallet Private Key":"Privater Schlüssel des Paperwallets","Participants":"Teilnehmer","Passphrase":"Passphrase","Password":"Passwort","Password required. Make sure to enter your password in advanced options":"Passwort erforderlich. Geben Sie Ihr Passwort in den erweiterten Optionen ein","Paste invitation here":"Einladung hier einfügen","Paste the backup plain text code":"Den Klartext der Sicherung einfügen","Paste your paper wallet private key here":"Privaten Schlüssel des Paperwallets hier einfügen","Pasted from clipboard":"Aus der Zwischenablage eingefügt","Pay To":"Zahle an","Payment Accepted":"Zahlung angenommen","Payment accepted, but not yet broadcasted":"Zahlung akzeptiert, aber noch nicht übermittelt","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Zahlung akzeptiert. Sie wird durch Glidera übermittelt. Falls ein Problem auftritt, kann sie nach einer Wartezeit von 6 Stunden gelöscht werden.","Payment details":"Zahlungsdetails","Payment expires":"Zahlung läuft ab","Payment Proposal":"Zahlungsvorschlag","Payment Proposal Created":"Zahlungsvorschlag erstellt","Payment Proposal Rejected":"Zahlungsvorschlag abgelehnt","Payment Proposal Rejected by Copayer":"Zahlungsvorschlag wurde vom Copayer abgelehnt","Payment Proposal Signed by Copayer":"Zahlungsvorschlag wurde vom Copayer abgezeichnet","Payment Proposals":"Zahlungsvorschläge","Payment Protocol Invalid":"Ungültiges Zahlungsprotokoll","Payment Protocol not supported on Chrome App":"Zahlungsprotokoll wird nicht von der Chrome App unterstützt","Payment Rejected":"Zahlung abgelehnt","Payment request":"Zahlungsanforderung","Payment Sent":"Zahlung gesendet","Payment to":"Zahlung an","Pending Confirmation":"Ausstehende Bestätigung","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Wallet dauerhaft löschen. DIESE AKTION KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN","Personal Wallet":"Persönliches Wallet","Please enter the recovery phrase":"Bitte geben Sie die Wiederherstellungsphrase ein","Please enter the required fields":"Bitte die benötigten Felder ausfüllen","Please enter the wallet recovery phrase":"Bitte geben Sie die Wallet-Wiederherstellungsphrase ein","Please tap the words in order to confirm your backup phrase is correctly written.":"Bitte tippen Sie auf die Wörter, um zu bestätigen, dass Ihre Backup-Phrase richtig geschrieben ist.","Please upgrade Copay to perform this action":"Bitte Copay aktualisieren, um diese Aktion auszuführen","Please wait to be redirected...":"Bitte warten Sie bis Sie umgeleitet werden...","Please, select your backup file":"Bitte die Sicherungsdatei wählen","Polish":"Polnisch","Preferences":"Einstellungen","Preparing backup...":"Sicherung wird vorbereitet...","preparing...":"in Arbeit...","Press again to exit":"Zum Beenden erneut drücken","Priority":"höchste Priorität","Private key is encrypted, cannot sign":"Der private Schlüssel ist verschlüsselt, signieren ist nicht möglich","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Pushbenachrichtigungen für Copay sind derzeit deaktiviert. Aktivieren sie Sie in den Einstellungen.","QR Code":"QR-Code","QR-Scanner":"QR-Scanner","Receive":"Empfangen","Received":"Empfangen","Recipients":"Empfänger","Recovery Phrase":"Wiederherstellungsphrase","Recovery phrase deleted":"Wiederherstellungsphrase gelöscht","Recreate":"Wiederherstellen","Recreating Wallet...":"Wallet wiederherstellen...","Reject":"Ablehnen","Release Information":"Information zur Veröffentlichung","Remove":"Entfernen","Repeat password":"Passwort wiederholen","Repeat the password":"Passwort wiederholen","Repeat the spending password":"Berechtigungscode wiederholen","Request a specific amount":"Einen bestimmten Betrag anfordern","Request Spending Password":"Berechtigungscode abfragen","Required":"Benötigt","Required number of signatures":"Erforderliche Anzahl von Signaturen","Retrieving inputs information":"Eingänge werden abgerufen","Russian":"Pусский","Save":"Speichern","Scan addresses for funds":"Adresse auf neue Beträge überprüfen","Scan Fingerprint":"Fingerabdruck scannen","Scan Finished":"Überprüfung abgeschlossen","Scan status finished with error":"Überprüfung wurde mit Fehlern beendet","Scan Wallet Funds":"Prüfe Beträge des Wallets","Scan your fingerprint please":"Scannen Sie bitte Ihren Fingerabdruck","Scanning Wallet funds...":"Prüfe Wallet auf neue Beträge...","Search transactions":"Transaktionen durchsuchen","Search Transactions":"Transaktionen durchsuchen","Security preferences":"Sicherheitseinstellungen","See it on the blockchain":"Im Blockchain anzeigen","Select a backup file":"Eine Sicherungsdatei auswählen","Select a wallet":"Wallet wählen","Self-signed Certificate":"Selbstsigniertes Zertifikat","Send":"Senden","Send addresses by email":"Adressen per e-Mail versenden","Send bitcoin":"Bitcoins senden","Send by email":"Per E-Mail versenden","Send Max":"Alles senden","Sending":"Senden","Sending transaction":"Sende Transaktion","Sent":"Gesendet","Server response could not be verified":"Antwort des Servers konnte nicht verifiziert werden","Session log":"Sitzungsprotokoll","SET":"EINRICHTEN","Set default url":"Festlegen der Standard-URL","Set up a password":"Passwort einrichten","Set up a spending password":"Berechtigungscode einrichten","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Das Einrichten einer E-Mail Benachrichtigung schwächt die Privatsphäre, wenn der Wallet Service Anbieter kompromittiert wurde. Der Angreifer kann jedoch nur Wallet Adresse und Guthaben erfahren, mehr nicht.","Settings":"Einstellungen","Share address":"Adresse teilen","Share invitation":"Einladung teilen","Share this invitation with your copayers":"Einladung mit Copayern teilen","Share this wallet address to receive payments":"Geben Sie diese Adresse weiter um Zahlungen zu erhalten","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Um Zahlungen zu empfangen, die hier angegebene Adresse teilen. Um die Privatsphäre zu schützen wird nach jeder Nutzung eine neue Adresse erzeugt.","Shared Wallet":"Wallet teilen","Show advanced options":"Erweiterte Optionen anzeigen","Signatures rejected by server":"Signaturen wurden vom Server abgelehnt","Signing transaction":"Unterschreibe Transaktion","Single Address Wallet":"Wallet mit einer einzigen Adresse","Spanish":"Español","Specify Recovery Phrase...":"Wiederherstellungsphrase angeben...","Spend proposal is not accepted":"Zahlungsvorschlag wurde nicht akzeptiert","Spend proposal not found":"Zahlungsvorschlag wurde nicht gefunden","Spending Password needed":"Berechtigungscode erforderlich","Spending Passwords do not match":"Berechtigungscodes stimmen nicht überein","Success":"Erfolgreich","Super Economy":"Niedrigste Priorität","Sweep paper wallet":"Paperwallet löschen","Sweep Wallet":"Wallet löschen","Sweeping Wallet...":"Leere Wallet...","Tap and hold to show":"Anzeigen durch tippen und halten","Tap to retry":"Zum Wiederholen antippen","Terms of Use":"Nutzungsbedingungen","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Die Autoren der Software, Mitarbeiter und Partner von Bitpay, Inhaber von Urheberrechten und BitPay, Inc. können nicht Ihre privaten Schlüssel oder Kennwörter abrufen, wenn diese verloren gehen oder vergessen werden und können die Durchführung von Transaktionen, auch nach Bestätigungen, nicht garantieren, da sie keine Kontrolle über das Bitcoin-Netzwerk haben.","The derivation path":"Die Ableitungsstruktur","The Ledger Chrome application is not installed":"Die Chrome-Anwendung für Ledger ist nicht installiert","The password of the recovery phrase (if set)":"Das Passwort der Wiederherstellungsphrase (wenn eingestellt)","The payment was created but could not be completed. Please try again from home screen":"Die Zahlung wurde erzeugt, kann aber nicht abgeschlossen werden. Bitte erneut über die Startseite versuchen","The payment was removed by creator":"Die Zahlung wurde vom Ersteller entfernt","The recovery phrase could require a password to be imported":"Um die Wiederherstellungsphrase zu importieren könnte ein Passwort nötig sein","The request could not be understood by the server":"Die Anforderung konnte nicht vom Server interpretiert werden","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Die Software erzeugt kein Benutzerkonto, bei dem Bitpay oder sonstige Dritte als Finanzvermittler oder Verwalter der Bitcoin fungieren.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Die Software, die genutzt werden soll, fungiert als freies, quelloffenes und digitales mehrfachunterschriften Wallet.","The spend proposal is not pending":"Der Zahlungsvorschlag ist nicht ausstehend","The wallet \"{{walletName}}\" was deleted":"Wallet \"{{walletName}}\" wurde gelöscht","The Wallet Recovery Phrase could require a password to be imported":"Um die Wiederherstellungsphrase zu importieren könnte ein Passwort nötig sein","The wallet service URL":"Die URL des Wallet-Diensts","There are no wallets to make this payment":"Es gibt keine Wallets, um diese Zahlung auszuführen","There is a new version of Copay. Please update":"Es gibt eine neue Version von Copay. Bitte aktualisieren","There is an error in the form":"Es ist ein Fehler im Formular aufgetreten","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"Diese Wiederherstellungsphrase entstand mit einem Passwort. Zur Wiederherstellung der Wallet sind die Wiederherstellungsphrase und das Passwort erforderlich.","This transaction has become invalid; possibly due to a double spend attempt.":"Diese Transaktion ist wurde ungültig; dies kann durch eine versuchte Doppelzahlung verursacht worden sein.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Dieses Wallet ist nicht beim angegebenen Bitcore Wallet Service (BWS) registriert. Bitte aus den lokalen Informationen wiederherstellen","Time":"Zeit","To":"An","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Voraussetzungen um dieses geteilte {{index.m}}-{{index.n}} Wallet wiederherzustellen","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"Unter voller Ausschöpfung geltenden Rechts wird diese Software \"wie besehen\" zur Verfügung gestellt ohne irgendwelche Zusicherungen oder Gewährleistungen aller Art, ausdrücklich oder stillschweigend, einschließlich aber nicht beschränkt auf Garantien der Handelstauglichkeit, Brauchbarkeit oder eines bestimmten Zwecks oder der Nichtverletzung der Rechte Dritter.","too long!":"zu lang!","Total Locked Balance":"Ingesamt gesperrter Gesamtsaldo","Total number of copayers":"Gesamtanzahl der Copayer","Touch ID Failed":"Touch-ID gescheitert","Transaction":"Transaktion","Transaction already broadcasted":"Transaktion wurde bereits übermittelt","Transaction History":"Transaktionsverlauf","Translation Credits":"Danksagung an die Übersetzer","Translators":"Übersetzer","Try again":"Nochmal versuchen","Type the Recovery Phrase (usually 12 words)":"Wiederherstellungsphrase eingeben (in der Regel 12 Wörter)","Unconfirmed":"Unbestätigt","Unit":"Währungseinheit","Unsent transactions":"Nicht vesendete Transaktionen","Updating transaction history. Please stand by.":"Aktualisieren des Transaktionsverlaufs. Bitte warten.","Updating Wallet...":"Wallet aktualisieren...","Use Unconfirmed Funds":"Unbestätigte Mittel einsetzen","Validating recovery phrase...":"Überprüfe Wiederherstellungsphrase...","Validating wallet integrity...":"Überprüfe Wallet-Integrität...","Version":"Version","View":"Ansicht","Waiting for copayers":"Warte auf copayer","Waiting for Ledger...":"Warte auf Ledger...","Waiting for Trezor...":"Warte auf Trezor...","Waiting...":"Warte...","Wallet already exists":"Wallet exstiert bereits","Wallet already in Copay":"Wallet ist bereits in Copay","Wallet Configuration (m-n)":"Wallet-Konfiguration (m-n)","Wallet Export":"Wallet-Export","Wallet Id":"Wallet-Id","Wallet incomplete and broken":"Wallet unvollständig oder defekt","Wallet Information":"Wallet-Informationen","Wallet Invitation":"Wallet Einladung","Wallet Invitation is not valid!":"Wallet Einladung nicht gültig!","Wallet is full":"Maximale Teilnehmerzahl erreicht","Wallet is locked":"Wallet ist gesperrt","Wallet is not complete":"Wallet ist unvollständig","Wallet name":"Name des Wallets","Wallet Name (at creation)":"Wallet-Name (bei der Erzeugung)","Wallet needs backup":"Wallet braucht Sicherung","Wallet Network":"Wallet-Netzwerk","Wallet not found":"Wallet nicht gefunden","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"Wallet ist nicht beim Wallet-Service registiert. Neu erzeugen mit \"Neues Wallet erzeugen\" und \"Erweiterte Optionen\" um die Wiederherstellungsphrase anzugeben","Wallet Preferences":"Wallet Voreinstellungen","Wallet Recovery Phrase":"Wallet-Wiederherstellungsphrase","Wallet Recovery Phrase is invalid":"Wallet-Wiederherstellungsphrase ist ungültig","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"Wallet-Wiederherstellungsphrase ist nicht verfügbar. Export über Erweitert > Wallet exportieren ist noch möglich.","Wallet service not found":"Wallet-Dienst nicht gefunden","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"Warnung: Ableitung der Schlüssel funktioniert nicht auf diesem Gerät/Wallet. Aktionen können nicht mit dieser Wallet durchgeführt werden.","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNUNG: Ohne das Hinzufügen des privaten Schlüssels, ist es möglich das Guthaben und die Transaktionshistorie einzusehen, sowie Zahlungsvorschläge zu erzeugen. Allerdings können Vorschläge nicht ausgeführt (unterschrieben) werden und es ist kein Zugriff auf Guthaben möglich.","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"Warnung: Das Passwort kann nicht wiederhergestellt werden. Achten Sie darauf, es aufzuschreiben. Das Wallet kann nicht ohne das Passwort wiederhergestellt werden.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNUNG: Der private Schlüssel ist nicht verfügbar. Dieser Export ermöglicht das Guthaben und die Transaktionshistorie zu prüfen, sowie Zahlungsvorschläge zu erzeugen. Allerdings können Vorschläge nicht ausgeführt (unterschrieben) werden und so ist kein Zugriff auf Guthaben möglich.","Warning: this transaction has unconfirmed inputs":"Warnung: Diese Transaktion hat unbestätigte Eingänge","WARNING: UNTRUSTED CERTIFICATE":"WARNUNG: NICHT VERTRAUENSWÜRDIGES ZERTIFIKAT","WARNING: Wallet not registered":"WARNUNG: Wallet nicht registriert","Warning!":"Warnung!","We reserve the right to modify this disclaimer from time to time.":"Wir behalten uns das Recht vor, diese Erklärung von Zeit zu Zeit zu ändern.","WELCOME TO COPAY":"Willkommen bei COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Solange sich diese Software im Betastadium befindet und weiterhin durch Feedback der Open-Source Nutzer und Entwickler-Community verbessert wird, können wir nicht garantieren, dass diese frei von Fehlern ist.","Write your wallet recovery phrase":"Wallet-Wiederherstellungsphrase notieren","Wrong number of recovery words:":"Falsche Anzahl von Wiederherstellungswörtern:","Wrong spending password":"Falscher Berechtigungscode","Yes":"Ja","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Sie bestätigen, die Software nach eigenem Ermessen und in Übereinstimmung der anwendbaren Gesetze zu verwenden.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Sie sind verantwortlich für die Verwahrung Ihrer Kennwörter, privaten Schlüsselpaaren, PINs und anderen Codes, die zum Zugriff auf die Software verwendet werden.","You assume any and all risks associated with the use of the software.":"Sie übernehmen allen Risiken im Zusammenhang mit der Nutzung der Software.","You backed up your wallet. You can now restore this wallet at any time.":"Sie haben Ihre Wallet gesichert. Sie können sie nun jederzeit wiederherstellen.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Das Wallet kann sicher auf einem anderen Gerät installiert und von mehreren Geräten gleichzeitig verwendet werden.","You do not have any wallet":"Kein Wallet vorhanden","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"Sie benötigen die Wallet-Wiederherstellungsphrase, um Ihre persönliche Wallet wiederherzustellen. Schreiben Sie sie auf und bewahren Sie sie an einem sicheren Ort auf.","Your nickname":"Name des Teilnehmers","Your password":"Passwort","Your spending password":"Ihr Berechtigungscode","Your wallet has been imported correctly":"Das Wallet wurde korrekt importiert","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"Ihr Wallet wird verschlüsselt werden. Der Berechtigungscode kann nicht wiederhergestellt werden. Achten Sie darauf, ihn aufzuschreiben","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Die Wallet-Wiederherstellungsphrase und der Zugriff auf den Server, die die Wallet ursprünglich erzeugten. Es werden noch {{index.m}} Schlüssel benötigt."}); - gettextCatalog.setStrings('el', {"(possible double spend)":"(πιθανό διπλό ξόδεμα)","(Trusted)":"(Εμπιστευτικό)","[Balance Hidden]":"[Υπόλοιπο Κρυμένο]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}}, θα προεξοφληθεί ώς τέλος του δικτύου bitcoin","{{feeRateStr}} of the transaction":"{{feeRateStr}} της συναλλαγής","{{index.m}}-of-{{index.n}}":"{{index.m}}-του-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} περισσότερα","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} οι συναλλαγές μεταφορτώθηκαν","{{item.m}}-of-{{item.n}}":"{{item.m}}-του-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"Μια πρόταση πληρωμής μπορεί να διαγραφεί εάν 1) είστε ο δημιουργός, και κανένας άλλος χρήστης του copay δεν έχει υπογράψει, ή 2) έχουν περάσει 24 ώρες απο την ώρα που η πρόταση δημιουργήθηκε.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"ΕΑΝ ΧΑΣΕΤΕ ΤΗΝ ΠΡΟΣΒΑΣΗ ΝΑ ΣΑΣ ΣΤΟ ΠΟΡΤΟΦΌΛΙ COPAY Ή ΣΤΑ ΚΡΥΠΤΟΓΡΑΦΗΜΕΝΑ ΙΔΙΩΤΙΚΑ ΣΑΣ ΚΛΕΙΔΙΑ ΚΑΙ ΔΕΝ ΑΠΟΘΗΚΕΥΣΑΤΕ ΧΩΡΙΣΤΆ ΕΝΑ ΑΝΤΙΓΡΑΦΟ ΑΣΦΑΛΕΙΑΣ ΤΟΥ ΠΟΡΤΟΦΟΛΙΟΥ ΚΑΙ ΤΟΥ ΑΝΤΙΣΤΟΙΧΟΥ ΚΩΔΙΚΟΥ ΠΡΌΣΒΑΣΗΣ, ΑΠΟΔΕΧΕΣΤΕ ΚΑΙ ΣΥΜΦΩΝΕΙΤΕ ΟΤΙ ΟΠΟΙΑΔΗΠΟΤΕ ΠΟΣΟΤΗΤΑ BITCOIN ΠΟΥ ΕΧΕΤΕ ΣΥΣΧΕΤΙΣΕΙ ΜΕ ΤΟ ΠΟΡΤΟΦΟΛΙ ΤΟΥ COPAY ΘΑ ΓΙΝΟΥΝ ΑΠΡΟΣΠΕΛΑΣΤΑ.","A multisignature bitcoin wallet":"Ένα πορτοφόλι bitcoin με δυνατότητα πολλαπλών υπογραφών","About Copay":"Σχετικά με το Copay","Accept":"Αποδοχή","Account":"Λογαριασμός","Account Number":"Αριθμός λογαριασμού","Activity":"Δραστηριότητα","Add a new entry":"Προσθέστε Καταχώρηση","Add a Password":"Προσθέστε Κωδικό","Add an optional password to secure the recovery phrase":"Προσθέστε προαιρετικό κωδικό για να ασφαλίσετε τη φράση επαναφοράς","Add comment":"Προσθήκη σχολίου","Add wallet":"Προσθήκη Πορτοφολιού","Address":"Διεύθυνση","Address Type":"Τύπος Διεύθυνσης","Advanced":"Για προχωρημένους","Alias":"Ψευδώνυμο","Alias for {{index.walletName}}":"Ψευδώνυμο για {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Όλες οι εισηγήσεις στην μετάφραση του Copay είναι ευπρόσδεκτες. Εγγραφείτε στο crowdin.com για να συμμετάσχετε στο έργο Copay","All transaction requests are irreversible.":"Όλες οι αιτήσεις για συναλλαγές είναι αμετάκλητες.","Alternative Currency":"Εναλλακτικό Νόμισμα","Amount":"Ποσό","Amount below minimum allowed":"Ποσό χαμηλότερο από το κατώτερο επιτρεπόμενο","Amount in":"Ποσό εισόδου","Are you sure you want to delete the recovery phrase?":"Σίγουρα θέλετε να σβήσετε τη φράση επαναφοράς;","Are you sure you want to delete this wallet?":"Είσαι σίγουρος ότι θέλετε να διαγράψετε αυτό το πορτοφόλι?","Auditable":"Ελέγξιμο","Available Balance":"Διαθέσιμο Υπόλοιπο","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Μέσος χρόνος επιβεβαίωσης: {{fee.nbBlocks * 10}} λεπτά","Back":"Πίσω","Backup":"Αντίγραφο Ασφαλείας","Backup failed":"Αποτυχία αντιγράφου επαναφοράς","Backup Needed":"Απαιτείται αντίγραφο επαναφοράς","Backup now":"Πάρτε Αντίγραφο Ασφαλείας τώρα","Bad wallet invitation":"Κακή πρόσκληση πορτοφολιού","Balance By Address":"Υπόλοιπο ανά διεύθυνση","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Για να μπορέσετε να λάβετε κεφάλαια, πρέπει πρώτα να δημιουργήσετε ένα αντίγραφο ασφαλείας (backup). Στην περίπτωση που χαθεί αυτή η συσκευή, θα είναι αδύνατο να έχετε πρόσβαση στα κεφάλαια σας χωρίς το αντίγραφο ασφαλείας.","BETA: Android Key Derivation Test:":"ΒΕΤΑ: Δοκιμή παραγωγής κλειδιού:","BIP32 path for address derivation":"διαδρομή BIP32 για παραγωγή διεύθυνσης","Bitcoin address":"Διεύθυνση Bitcoin","Bitcoin Network Fee Policy":"Πολιτική Χρέωσης Δικτύου Bitcoin","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Οι συναλλαγές Bitcoin μπορεί να περιλαμβάνουν μια αμοιβή που εισπράττουν οι miners του δικτύου. Όσο υψηλότερο είναι αυτό το τέλος, τόσο μεγαλύτερο είναι και το κίνητρο ενός miner να συμπεριλάβει αυτή τη συναλλαγή σε ένα block. Οι παρουσιαζόμενη αμοιβή καθορίζεται με βάση το φορτίο του δικτύου και την επιλεγμένη πολιτική.","Bitcoin URI is NOT valid!":"Το σύστημα Bitcoin URI δεν είναι έγκυρο!","Broadcast Payment":"Μετάδοση Πληρωμής","Broadcasting transaction":"Μεταδίδοντας την συναλλαγή","Browser unsupported":"Ο πλοηγός δέν υποστηρίζεται","Calculating fee":"Υπολογισμός αμοιβής","Cancel":"Άκυρο","Cancel and delete the wallet":"Ακύρωση και διαγραφή του πορτοφολιού","Cannot create transaction. Insufficient funds":"Δεν ήταν δυνατή η δημιουργία συναλλαγής. Ανεπαρκή κεφάλαια","Cannot join the same wallet more that once":"Δεν μπορείτε να ενταχθείτε στο ίδιο πορτοφόλι περισσότερες απο μία φορές","Cannot sign: The payment request has expired":"Δεν ήταν δυνατή η υπογραφή: Η αίτηση πληρωμής έχει λήξει","Certified by":"Πιστοποιήθηκε από","Changing wallet alias only affects the local wallet name.":"Αλλάζοντας το ψευδώνυμο του πορτοφολιού επηρεάζει μόνο το τοπικό όνομα πορτοφολιού.","Chinese":"Κινεζικά","Choose a backup file from your computer":"Επιλέξτε ένα αντίγραφο ασφαλείας απο τον υπολογιστή σας","Clear cache":"Εκκαθάριση προσωρινής μνήμης (cache)","Close":"Κλείσιμο","Color":"Χρώμα","Comment":"Σχόλιο","Commit hash":"Δέσμευση λύσης","Confirm":"Επιβεβαίωση","Confirm your wallet recovery phrase":"Επιβεβαιώσετε τη φράση αποκατάστασης για το πορτοφόλι σας","Confirmations":"Επιβεβαιώσεις","Congratulations!":"Συγχαρητήρια!","Connecting to Coinbase...":"Συνδέεται στο Coinbase...","Connecting to Glidera...":"Συνδέεται στο Glidera...","Connection reset by peer":"Επαναφορά σύνδεσης","Continue":"Συνεχίστε","Copayer already in this wallet":"Copayers ήδη σε αυτό το πορτοφόλι","Copayer already voted on this spend proposal":"Copayer που έχουν ήδη ψηφίσει αυτή την πρόταση","Copayer data mismatch":"Ασυμφωνία δεδομένων του copayer","Copayers":"Μέλη του πορτοφολιού Copay","Copied to clipboard":"Αντιγράφηκε στο πρόχειρο","Copy this text as it is to a safe place (notepad or email)":"Αντιγράψτε αυτο το κείμενο ώς έχει σε ασφαλές μέρος (σε εφαρμογή κειμένου ή ηλεκτρονικό ταχυδρομείο)","Copy to clipboard":"Αντιγραφή στο πρόχειρο","Could not access the wallet at the server. Please check:":"Δεν ήταν δυνατή η πρόσβαση στο πορτοφόλι στον διακομιστή. Παρακαλώ ελέγξετε:","Could not access wallet":"Δεν ήταν δυνατή η πρόσβαση στο πορτοφόλι","Could not access Wallet Service: Not found":"Δεν ήταν δυνατή η πρόσβαση στην υπηρεσία του πορτοφολιού: δεν βρέθηκε","Could not broadcast payment":"Δεν μπορέσαμε να μεταδώσουμε την πληρωμή","Could not build transaction":"Δε μπορώ να δημιουργήσω τη συναλλαγή","Could not create address":"Δεν μπορέσαμε να δημιουργήσουμε την διεύθυνση","Could not create payment proposal":"Δεν ήταν δυνατή η δημιουργία πρότασης πληρωμής","Could not create using the specified extended private key":"Δεν ήταν δυνατή η δημιουργία χρησιμοποιώντας το συγκεκριμένο ιδιωτικό κλειδί επέκτασης","Could not create using the specified extended public key":"Δεν ήταν δυνατή η δημιουργία χρησιμοποιώντας το συγκεκριμένο εκτεταμένο δημόσιο κλειδί","Could not create: Invalid wallet recovery phrase":"Δεν ήταν δυνατή η δημιουργία: Μη έγκυρη φράση αποκατάστασης πορτοφολιού","Could not decrypt file, check your password":"Δεν ήταν δυνατή η αποκρυπτογράφηση του αρχείου, ελέγξτε τον κωδικό σας","Could not delete payment proposal":"Δεν είναι δυνατή η διαγραφή της πρότασης πληρωμής","Could not fetch payment information":"Δεν ήταν δυνατή η ανάκτηση των στοιχείων πληρωμής","Could not get fee value":"Δεν ήταν δυνατή η λήψη της αξίας της αμοιβής","Could not import":"Η εισαγωγή απέτυχε","Could not import. Check input file and spending password":"Δεν ήταν δυνατή η εισαγωγή. Ελέγξτε το αρχείο και τον κωδικό πρόσβασης","Could not join wallet":"Δεν μπορείτε να συμμετάσχετε στο πορτοφόλι","Could not recognize a valid Bitcoin QR Code":"Δεν ήταν δυνατή η αναγνώριση ενός έγκυρου κωδικού QR για Βitcoin","Could not reject payment":"Δεν μπορέσαμε να απορρίψουμε την πληρωμή","Could not send payment":"Δεν είναι δυνατή η αποστολή της πληρωμής","Could not update Wallet":"Δεν ήταν δυνατή η ενημέρωση του πορτοφολιού","Create":"Δημιουργία","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Δημιουργία {{requiredCopayers}} των {{totalCopayers}} του πορτοφολιού","Create new wallet":"Δημιουργήστε νέο πορτοφόλι","Create, join or import":"Δημιουργία, συμμετοχή ή εισαγωγή","Created by":"Δημιουργήθηκε από","Creating transaction":"Δημιουργία συναλλαγής","Creating Wallet...":"Δημιουργία του Πορτοφολιού...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Σημερινό ποσοστό αμοιβής για αυτήν την πολιτική: {{fee.feePerKBUnit}}/kiB","Czech":"Τσέχικα","Date":"Ημερομηνία","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Η αποκρυπτογράφηση ενός χάρτινου πορτοφολιού μπορεί να πάρει περίπου 5 λεπτά σε αυτή την συσκευή. Κάντε υπομονή και κρατήστε την εφαρμογή ανοικτή.","Delete it and create a new one":"Διαγράψετε το και δημιουργήστε ένα νέο","Delete Payment Proposal":"Διαγράψτε την Πρόταση Πληρωμής","Delete recovery phrase":"Σβήσιμο φράσης επαναφοράς","Delete Recovery Phrase":"Σβήσιμο φράσης επαναφοράς","Delete wallet":"Διαγραφή Πορτοφολιού","Delete Wallet":"Διαγραφή Πορτοφολιού","Deleting Wallet...":"Διαγραφή πορτοφολιού...","Derivation Path":"Διαδρομή παραγωγής","Derivation Strategy":"Στρατηγική παραγωγής","Description":"Περιγραφή","Details":"Λεπτομέρειες","Disabled":"Απενεργοποιημένο","Do not include private key":"Μην συμπεριλάβετε το ιδιωτικό κλειδί","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Δεν βλέπετε τη γλώσσα σας στο Crowdin; Επικοινωνήστε με τον ιδιοκτήτη στο Crowdin! Θα θέλαμε να υποστηρίξουμε τη γλώσσα σας.","Done":"Ολοκλήρωση","Download":"Μεταφόρτωση","Economy":"Οικονομία","Edit":"Έπεξεργασία","Edit comment":"Επεξεργασία σχολίου","Edited by":"Επεξεργασία από","Email for wallet notifications":"Το ηλεκτρονικό σας ταχυδρομείο για τις ειδοποιήσεις του πορτοφόλιού σας","Email Notifications":"Ειδοποιήσεις Email","Empty addresses limit reached. New addresses cannot be generated.":"Το όριο άδειων διευθύνσεων ξεπεράστηκε. Δεν μπορούν να δημιουργηθούν νέες διευθύνσεις.","Enable Coinbase Service":"Ενεργοποιήση υπηρεσίας Coinbase","Enable Glidera Service":"Ενεργοποίηση υπηρεσίας Glidera","Enable push notifications":"Ενεργοποίηση ειδοποιήσεων push","Encrypted export file saved":"Η εξαγωγή κρυπτογραφημένου αρχείου αποθηκεύτηκε","Enter the recovery phrase (BIP39)":"Εισάγετε τη φράση αποκατάστασης (BIP39)","Enter your password":"Παρακαλώ εισάγετε τον κωδικό σας","Enter your spending password":"Εισάγετε τον κωδικό πληρωμών","Error at Wallet Service":"Σφάλμα στην υπηρεσία του πορτοφολιού","Error creating wallet":"Σφάλμα στην δημιουργία πορτοφολιού","Expired":"Έληξε","Expires":"Λήγει","Export options":"Επιλογές εξαγωγής","Export to file":"Εξαγωγή σε αρχείο","Export Wallet":"Εξαγωγή πορτοφολιού","Exporting via QR not supported for this wallet":"Η εξαγωγή μέσω QR δεν υποστηρίζεται για αυτο το πορτοφόλι","Extended Public Keys":"Εκτεταμένα δημόσια κλειδιά","Family vacation funds":"Χρήματα διακοπών της οικογένειας","Fee":"Αμοιβή","Fetching Payment Information":"Λήψη Πληροφοριών Πληρωμής","Finish":"Τερματισμός","French":"Γαλλικά","Funds are locked by pending spend proposals":"Τα χρήματα είναι κλειδωμένα από εν αναμονή προτάσεις αποστολής","Funds received":"Χρήματα ελήφθησαν","Generate new address":"Δημιουργία νέας διεύθυνσης","Generate QR Code":"Δημιουργία Κώδικα QR","Generating .csv file...":"Δημιουργία .csv αρχείου...","German":"Γερμανικά","Getting address for wallet {{selectedWalletName}} ...":"Λήψη διεύθυνσης για το πορτοφόλι {{selectedWalletName}} ...","Hardware wallet":"Υλικό πορτοφόλι","Hide advanced options":"Απόκρυψη Προχωρημένων επιλογών","I affirm that I have read, understood, and agree with these terms.":"Βεβαιώνω ότι έχω διαβάσει, κατανοήσει και συμφωνήσει με αυτούς τους όρους.","Import":"Εισαγωγή","Import backup":"Εισαγωγή αντιγράφου ασφαλείας","Import wallet":"Εισαγωγή πορτοφολιού","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"Σε καμία περίπτωση οι συντάκτες του λογισμικού, οι συνεργάτες του Bitpay, οι κατόχοι πνευματικών δικαιωμάτων, ή η BitPay α.ε. ευθύνεται για οποιαδήποτε αξίωση, ζημία ή άλλη ευθύνη, είτε βαση κάποιας σύμβασης, αδικοπραξίας, ή άλλο, που προκύπτει από την σχέση σας με το λογισμικό.","Incorrect address network":"Εσφαλμένη διεύθυνση δικτύου","Insufficient funds":"Ανεπαρκές χρηματικό υπόλοιπο","Insufficient funds for fee":"Ανεπαρκής χρηματοδότηση για την αμοιβή","Invalid":"Μη έγκυρο","Invalid address":"Μη έγκυρη διεύθυνση","Invitation to share a Copay Wallet":"Πρόσκληση για τον διαμοιρασμό ενός πορτοφολιού Copay","Japanese":"Ιαπωνικά","John":"Ιωάννης","Join":"Συμμετοχή","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Συμμετάσχετε στο πορτοφόλι μου Copay. Εδώ είναι ο κωδικός πρόσκλησης: {{secret}} μπορείτε να κατεβάσετε το Copay για το τηλέφωνο σας ή τον υπολογιστή σας στο https://copay.io","Join shared wallet":"Συμμετοχή σε κοινόχρηστο πορτοφόλι","Joining Wallet...":"Εισαγωγή στο Πορτοφόλι...","Language":"Γλώσσα","Last Wallet Addresses":"Διευθύνσεις τελευταίων πορτοφολιών","Loading...":"Φόρτωση...","locked by pending payments":"κλειδωμένο από εκκρεμούσες πληρωμές","Locktime in effect. Please wait to create a new spend proposal":"Κλείδωμα σε ισχύ. Σας παρακαλώ περιμένετε για να δημιουργήσετε μια νέα πρόταση","Locktime in effect. Please wait to remove this spend proposal":"Κλείδωμα σε ισχύ. Σας παρακαλώ περιμένετε για να αφαιρέσετε αυτή την πρόταση","Make a payment to":"Κάντε μια πληρωμή σε","me":"Εγώ","Me":"Εγώ","Memo":"Σημείωση","Merchant message":"Μήνυμα Εμπόρου","Message":"Μήνυμα","Missing parameter":"Λείπει παράμετρος","Moved":"Μετακινήθηκε","Multiple recipients":"Πολλαπλοί παραλήπτες","My Bitcoin address":"Η διεύθυνση Bitcoin μου","My contacts":"Οι επαφές μου","My wallets":"Τα πορτοφόλια μου","Network":"Δίκτυο","Network connection error":"Σφάλμα σύνδεσης δικτύου","New Payment Proposal":"Νέα Πρόταση Πληρωμής","No transactions yet":"Δεν υπάρχουν συναλλαγές ακόμα","Normal":"Κανονική","Not authorized":"Δεν επιτρέπεται","Not valid":"Δεν είναι έγκυρη","Note":"Σημείωση","optional":"προαιρετικό","Paper Wallet Private Key":"Προσωπικό κλειδί χάρτινου πορτοφολιού","Participants":"Συμμετέχοντες","Passphrase":"Φράση κωδικός","Password":"Κωδικός πρόσβασης","Paste invitation here":"Επικολλήστε την πρόσκληση σας εδώ","Paste the backup plain text code":"Επικολλήστε τον κώδικα δημιουργίας αντιγράφων ασφαλείας εδώ","Pay To":"Πληρωμή Πρός","Payment Accepted":"Πληρωμή Αποδεκτή","Payment details":"Λεπτομέρειες πληρωμής","Payment Proposal":"Πρόταση Πληρωμής","Payment Proposal Created":"Πρόταση Πληρωμής Δημιουργήθηκε","Payment Proposal Rejected":"Πρόταση Πληρωμής Απορρίφθηκε","Payment Proposal Rejected by Copayer":"Το Copayer Απέρριψε την Πρόταση Πληρωμής","Payment Proposal Signed by Copayer":"Η Πρόταση Πληρωμής Υπογράφηκε από το Copayer","Payment Proposals":"Πρόταση Πληρωμής","Payment Protocol not supported on Chrome App":"Το Πρωτόκολλο Πληρωμής δεν υποστηρίζεται στην εφαρμογή Chrome","Payment Rejected":"Πληρωμή Απερρίφθη","Payment request":"Αίτηση πληρωμής","Payment Sent":"Πληρωμή Εστάλη","Payment to":"Πληρωμή σε","Pending Confirmation":"Υπό επιβεβαίωση","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Να διαγράφεί μόνιμα αυτό το πορτοφόλι? ΑΥΤΗ Η ΕΝΕΡΓΕΙΑ ΔΕΝ ΜΠΟΡΕΙ ΝΑ ΑΝΤΙΣΤΡΑΦΕΙ","Personal Wallet":"Προσωπικό πορτοφόλι","Please enter the required fields":"Παρακαλώ εισάγετε τα απαιτούμενα πεδία","Please upgrade Copay to perform this action":"Παρακαλώ αναβαθμίστε το Copay για να εκτελέσετε αυτήν την ενέργεια","Please, select your backup file":"Παρακαλώ, επιλέξτε το αρχείο αντιγράφου ασφαλείας","Polish":"Πολωνικά","Preferences":"Προτιμήσεις","Preparing backup...":"Προετοιμασία δημιουργίας αντιγράφων ασφαλείας...","preparing...":"Προετοιμασία...","Press again to exit":"Πιέστε ξανά για έξοδο","Priority":"Προτεραιότητα","Private key is encrypted, cannot sign":"Το ιδιωτικό κλειδί είναι κρυπτογραφημένο, η υπογραφή δεν ήταν εφικτή","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Οι ειδοποιήσεις push για Copay είναι απενεργοποιημένη αυτήν τη στιγμή. Ενεργοποιήστε τες στις Ρυθμίσεις της εφαρμογής.","QR Code":"Κωδικός QR","QR-Scanner":"Σαρωτής QR","Receive":"Λάβετε","Received":"Ληφθέντα","Recipients":"Παραλήπτες","Recovery Phrase":"Φράση ανάκτησης","Recovery phrase deleted":"Η Φράση Ανάκτησης διαγράφηκε","Recreate":"Αναδημιουργία","Recreating Wallet...":"Αναδημιουργία πορτοφολιού...","Reject":"Απόρριψη","Release Information":"Πληροφορίες Έκδοσης","Remove":"Αφαίρεση","Repeat password":"Επανάληψη κωδικού","Repeat the password":"Επανάληψη κωδικού","Repeat the spending password":"Επανάληψη κωδικού πληρωμών","Request a specific amount":"Ζητήστε ένα συγκεκριμένο ποσό","Request Spending Password":"Αίτηση κωδικού πληρωμών","Required":"Απαιτείτε","Required number of signatures":"Απαιτούμενος αριθμός υπογραφών","Retrieving inputs information":"Ανάκτηση πληροφοριών εισαγωγής","Russian":"Ρωσσικά","Save":"Αποθήκευση","Scan addresses for funds":"Σάρωση διευθύνσεων για χρήματα","Scan Fingerprint":"Σάρωση δακτυλικού αποτυπωμάτως","Scan Finished":"Η σάρωση ολοκληρώθηκε","Scan status finished with error":"Η σάρωση έχει τελειώσει με σφάλματα","Scan Wallet Funds":"Σάρωση κεφαλαίων πορτοφολιού","Scan your fingerprint please":"Σαρώστε το δακτυλικό σας αποτύπωμα","Scanning Wallet funds...":"Σάρωση χρημάτων Πορτοφολιού...","Search transactions":"Αναζήτηση συναλλαγών","Search Transactions":"Αναζήτηση συναλλαγών","Security preferences":"Ρυθμίσεις ασφαλείας","See it on the blockchain":"Δείτε τη συναλλαγή στην αλυσίδα συναλλαγών","Select a backup file":"Επιλέξτε ένα αρχείο αντιγράφου ασφαλείας","Select a wallet":"Επιλέξτε ένα πορτοφόλι","Send":"Αποστολή","Send by email":"Αποστολή με email","Sent":"Εξερχόμενα","Session log":"Ημερολόγιο συνεδριών","SET":"Ορισμός","Set up a password":"Ορίστε έναν κωδικό πρόσβασης","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Ενεργοποιώντας τις ενημερώσεις μέσω ηλεκτρονικού ταχυδρομείου μπορεί να μειωθεί η ιδιωτικότητα σας, εάν ο πάροχος του πορτοφολιού παραβιαστεί. Οι πληροφορίες που θα διαθέτει ένας εισβολέας θα περιλαμβάνουν τις διευθύνσεις του πορτοφόλιου σας και το ποσόν των χρημάτων σας, αλλά τίποτα περισσότερο.","Share address":"Μοιραστείτε τη διεύθυνση","Share invitation":"Μοιραστείτε μια πρόσκληση","Share this invitation with your copayers":"Μοιραστείτε αυτήν την πρόσκληση με άλλους copayers","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Μοιραστείτε αυτή τη διεύθυνση πορτοφόλιού ώστε να λάβετε πληρωμές. Για την προστασία της ιδιωτικότητας σας, νέες διευθύνσεις δημιουργούνται αυτόματα μόλις χρησιμοποιήσετε τις παλιές.","Shared Wallet":"Κοινόχρηστο πορτοφόλι","Show advanced options":"Εμφάνιση προχωρημένων επιλογών","Signatures rejected by server":"Οι υπογραφές απορρίφθηκαν από το διακομιστή","Spanish":"Ισπανικά","Spend proposal is not accepted":"Η πρόταση δεν έγινε αποδεκτή","Spend proposal not found":"Η πρόταση δεν βρέθηκε","Success":"Επιτυχία","Tap to retry":"Πατήστε για να προσπαθήσετε ξανά","Terms of Use":"Όροι Χρήσης","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Οι συγγραφείς του λογισμικού, οι εργαζόμενοι και οι συνεργάτες του Bitpay, οι κατόχοι πνευματικών δικαιωμάτων, και η BitPay α.ε., δεν μπορούν να ανακτήσουν ιδιωτικά κλειδιά ή τους κωδικούς πρόσβασης σας, εάν χάσετε ή ξεχασετε αυτούς και δεν μπορούν να εγγυηθούν την επιβεβαίωση της συναλλαγής, δεδομένου ότι δεν έχουν τον έλεγχο του δικτύου Bitcoin.","The payment was created but could not be completed. Please try again from home screen":"Η πληρωμή δημιουργήθηκε, αλλά δεν ήταν δυνατό να ολοκληρωθεί. Παρακαλώ ξαναπροσπαθήστε από την αρχική οθόνη","The payment was removed by creator":"Η πληρωμή έχει αφαιρεθεί από τον δημιουργό της","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Το λογισμικό δεν αποτελεί ένα λογαριασμό όπου το BitPay ή άλλα τρίτα μέρη χρησιμεύουν ως ενδιάμεσοι χρηματοπιστωτικοί οργανισμοί ή θεματοφύλακες των bitcoin σας.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Το λογισμικό που πρόκειται να χρησιμοποιήσετε λειτουργεί ως ένα δωρεάν, ανοικτού κώδικα και πολλαπλών υπογραφών ψηφιακό πορτοφόλι.","The spend proposal is not pending":"Δεν εκκρεμεί η πρόταση","The wallet \"{{walletName}}\" was deleted":"Διαγράφηκε το πορτοφόλι \"{{walletName}}\"","There are no wallets to make this payment":"Δεν υπάρχουν πορτοφόλια για να πραγματοποιηθεί η πληρωμή","There is an error in the form":"Υπάρχει ένα λάθος στη φόρμα εισαγωγής","This transaction has become invalid; possibly due to a double spend attempt.":"Αυτή η συναλλαγή είναι άκυρη, πιθανόν λόγω μιας προσπάθειας διπλού ξοδέματος.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Το πορτοφόλι δεν έχει καταχωρηθεί στη Βάση Δεδομένων Πορτοφολιών Bitcore (BWS). Μπορείτε να την ξαναδημιουργήσετε από τις τοπικές πληροφορίες.","Time":"Ώρα","To":"Προς","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"Στο μέγιστο βαθμό που επιτρέπει το δίκαιο, το λογισμικό παρέχεται \"ως έχει\" και καμία δήλωση ή εγγύηση μπορεί να γίνει του κάθε είδους, ρητή ή σιωπηρή, συμπεριλαμβανομένων, αλλά μη περιορισμένων, των εγγυήσεων εμπορευσιμότητας, καταλληλότητας ή συγκεκριμένου σκοπού και νομιμότητας.","too long!":"πάρα πολύ μεγάλο μέγεθος!","Total Locked Balance":"Συνολικό Κλειδωμένο Υπόλοιπο","Transaction":"Συναλλαγή","Transaction already broadcasted":"Συναλλαγή που έχει ήδη μεταδοθεί","Translation Credits":"Λεπτομέρειες Μετάφρασης","Translators":"Μεταφραστές","Unconfirmed":"Ανεπιβεβαίωτες","Unit":"Μονάδα","Unsent transactions":"Μη Απεσταλμένες συναλλαγές","Updating Wallet...":"Ενημέρωση πορτοφολιού...","Use Unconfirmed Funds":"Χρήση Ανεπιβεβαίωτων Ποσών","Version":"Έκδοση","Waiting for copayers":"Αναμονή για copayers","Waiting...":"Σε αναμονή...","Wallet already exists":"Υπάρχει ήδη το πορτοφόλι","Wallet incomplete and broken":"Πορτοφόλι ελλιπές και χαλασμένο","Wallet Invitation":"Πρόσκληση πορτοφολιού","Wallet Invitation is not valid!":"Η πρόσκληση πορτοφολιού δεν είναι έγκυρη!","Wallet is full":"Το πορτοφόλι είναι γεμάτο","Wallet is not complete":"Το πορτοφόλι δεν είναι πλήρες","Wallet name":"Όνομα πορτοφολιού","Wallet not found":"Το πορτοφόλι δεν βρέθηκε","Wallet service not found":"Η υπηρεσία του πορτοφολιού δεν βρέθηκε","Warning: this transaction has unconfirmed inputs":"Προειδοποίηση: αυτή η συναλλαγή έχει ανεπιβεβαίωτες εισροές","WARNING: Wallet not registered":"Προειδοποίηση: Το πορτοφόλι δεν έχει καταχωρηθεί","Warning!":"Προειδοποίηση!","We reserve the right to modify this disclaimer from time to time.":"Διατηρούμε το δικαίωμα να τροποποιήσουμε αυτή την αποποίηση ευθυνών από καιρό σε καιρό.","WELCOME TO COPAY":"ΚΑΛΩΣ ΗΛΘΑΤΕ ΣΤΟ COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Ενώ το λογισμικό έχει υποβληθεί σε δοκιμή beta και συνεχίζει να βελτιώνεται από χρήστες ανοικτού κώδικα και την κοινότητα των προγραμματιστών, εμείς δεν μπορούμε να εγγυηθούμε ότι δεν θα υπάρξει κανένα σφάλμα στο λογισμικό.","Yes":"Ναι","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Αναγνωρίζετε ότι η χρήση αυτού του λογισμικού είναι στην κρίση σας και σε συμφωνία με όλους τους ισχύοντες νόμους.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Είστε υπεύθυνος για τη διαφύλαξή των κωδικών πρόσβασής σας, το ιδιωτικό ζεύγος κλειδιών, τετραψήφιων κωδικών PIN και οποιουσδήποτε άλλους κωδικούς που χρησιμοποιείτε για να έχετε πρόσβαση στο λογισμικό.","You assume any and all risks associated with the use of the software.":"Αναλάμβανετε κάθε κινδύνο που συνδέεται με τη χρήση του λογισμικού.","Your nickname":"Το ψευδώνυμό σας","Your password":"Ο κωδικός σας","Your wallet has been imported correctly":"Το πορτοφόλι σας έχει εισαχθεί σωστά"}); - gettextCatalog.setStrings('es', {"(possible double spend)":"(Posible doble gasto)","(Trusted)":"(De confianza)","[Balance Hidden]":"[Balance Oculto]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} se descontará por comisión de la red bitcoin","{{feeRateStr}} of the transaction":"{{feeRateStr}} de la transacción","{{index.m}}-of-{{index.n}}":"{{index.m}}-de-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} más","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} transacciones descargadas","{{item.m}}-of-{{item.n}}":"{{item.m}}-de-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Una propuesta de pago puede ser eliminada si 1) Ud. es el creador, y ningún otro copayer la haya firmado, o 2) hayan transcurrido 24 horas desde la creación de la propuesta.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"SI UD. PIERDE ACCESO A SU MONEDERO COPAY O A SUS CLAVES PRIVADAS ENCRIPTADAS Y NO HA GUARDADO POR SEPARADO UNA COPIA DE SEGURIDAD DE SU MONEDERO Y CONTRASEÑA CORRESPONDIENTES, USTED RECONOCE Y ACEPTA QUE CUALQUIER BITCOIN QUE HA ASOCIADO CON ESE MONEDERO COPAY SERÁ INACCESIBLE.","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"O 1 archivo exportado del monedero y el quórum restante de la frase de recuperación (por ejemplo en un monedero 3-5: 1 archivo exportado + 2 frases de recuperación del monedero de cualquiera de los otros copayers).","OR the wallet recovery phrase of all copayers in the wallet":"O la frase de recuperación de todos los copayers del monedero","OR the wallet recovery phrases of all copayers in the wallet":"O las frases de recuperación de todos los copayers del monedero","A multisignature bitcoin wallet":"Monedero multifirma de bitcoin","About Copay":"Acerca de Copay","Accept":"Aceptar","Account":"Cuenta","Account Number":"Número de cuenta","Activity":"Actividad","Add a new entry":"Agregar una nueva entrada","Add a Password":"Agregar una contraseña","Add an optional password to secure the recovery phrase":"Agregar una contraseña opcional para asegurar la frase de recuperación","Add comment":"Añadir comentario","Add wallet":"Agregar monedero","Address":"Dirección","Address Type":"Tipo de Dirección","Advanced":"Avanzado","Alias":"Alias","Alias for {{index.walletName}}":"Alias de {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Todas las contribuciones a la traducción de Copay son bienvenidas. Regístrese en crowdin.com y únase al proyecto Copay en","All transaction requests are irreversible.":"Todas las solicitudes de transacciones son irreversibles.","Alternative Currency":"Moneda Alternativa","Amount":"Importe","Amount below minimum allowed":"Cantidad por debajo del mínimo permitido","Amount in":"Importe en","Are you sure you want to delete the recovery phrase?":"¿Está seguro que quiere eliminar la frase de recuperación?","Are you sure you want to delete this wallet?":"¿Estas seguro de borrar este monedero?","Auditable":"Auditables","Available Balance":"Balance disponible","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Tiempo promedio de confirmación: {{fee.nbBlocks * 10}} minutos","Back":"Volver","Backup":"Copia de seguridad","Backup failed":"Falló la copia de seguridad","Backup Needed":"Se requiere hacer copia de seguridad","Backup now":"Realizar copia de seguridad ahora","Bad wallet invitation":"Invitación incorrecta al monedero","Balance By Address":"Balance por Dirección","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Antes de recibir fondos, es necesario hacer una copia de seguridad de su monedero. Si pierde este dispositivo, es imposible tener acceso a sus fondos sin una copia de seguridad.","BETA: Android Key Derivation Test:":"BETA: Prueba de derivación de claves Android:","BIP32 path for address derivation":"BIP32 para el camino de derivación de direcciones","Bitcoin address":"Dirección bitcoin","Bitcoin Network Fee Policy":"Política de Comisión de la Red Bitcoin","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Las transacciones de Bitcoin pueden incluir una comisión colectada por los mineros en la red. Cuanto mayor sea la comisión, mayor será el incentivo para que el minero incluya esa transacción en un bloque. Las comisiones actuales se determinan en base a la carga de la red y a la política seleccionada.","Bitcoin URI is NOT valid!":"¡Bitcoin URI no es válida!","Broadcast Payment":"Enviar Pago","Broadcasting transaction":"Finalizando transacción","Browser unsupported":"Navegador no soportado","Buy and Sell":"Comprar y Vender","Calculating fee":"Calculando comisión","Cancel":"Cancelar","Cancel and delete the wallet":"Cancelar y borrar el monedero","Cannot create transaction. Insufficient funds":"No se puede crear transacciones. Insuficiencia de fondos","Cannot join the same wallet more that once":"No puede unirse al mismo monedero más de una vez","Cannot sign: The payment request has expired":"No se pudo firmar: la solicitud de pago ha expirado","Certified by":"Certificado por","Changing wallet alias only affects the local wallet name.":"Cambiar el alias del monedero solo afecta al nombre del monedero local.","Chinese":"Chino","Choose a backup file from your computer":"Seleccione el archivo de copia de seguridad de su computadora","Clear cache":"Limpiar cache","Close":"Cerrar","Color":"Color","Comment":"Comentario","Commit hash":"Commit hash","Confirm":"Confirmar","Confirm your wallet recovery phrase":"Confirmar frase de recuperación del monedero","Confirmations":"Confirmaciones","Congratulations!":"¡Felicitaciones!","Connecting to Coinbase...":"Conectando a Coinbase...","Connecting to Glidera...":"Conectando a Glidera...","Connection reset by peer":"Conexión re establecida","Continue":"Continuar","Copayer already in this wallet":"Ya se encuentra en este monedero","Copayer already voted on this spend proposal":"Ya ha votado en esta propuesta de gasto","Copayer data mismatch":"Discrepancia en los datos del Copayer","Copayers":"Copayers","Copied to clipboard":"Copiado al portapapeles","Copy this text as it is to a safe place (notepad or email)":"Copiar el texto como esta en un lugar seguro (bloc de notas o correo electrónico)","Copy to clipboard":"Copiar al portapapeles","Could not access the wallet at the server. Please check:":"No se pudo acceder al monedero del servidor. Por favor verificar:","Could not access wallet":"No se pudo acceder al monedero","Could not access Wallet Service: Not found":"No se pudo acceder a Wallet Service: No encontrado","Could not broadcast payment":"No se pudo enviar el pago","Could not build transaction":"No se pudo construir la transacción","Could not create address":"No se pudo crear la dirección","Could not create payment proposal":"No se pudo crear la propuesta de pago","Could not create using the specified extended private key":"No se pudo crear el monedero usando la clave privada ingresada","Could not create using the specified extended public key":"No se pudo crear con la clave pública extendida especificada","Could not create: Invalid wallet recovery phrase":"No se pudo crear: frase de recuperación inválida","Could not decrypt file, check your password":"No se pudo descifrar el archivo, verifique su contraseña","Could not delete payment proposal":"No se pudo eliminar la propuesta de pago","Could not fetch payment information":"No se pudo obtener información del pago","Could not get fee value":"No se pudo obtener valor de la comisión","Could not import":"No se pudo importar","Could not import. Check input file and spending password":"No se pudo importar. Verifique el archivo y la contraseña para enviar","Could not join wallet":"No se pudo unir al monedero","Could not recognize a valid Bitcoin QR Code":"No se reconoció el código QR de Bitcoin válido","Could not reject payment":"No se pudo rechazar el pago","Could not send payment":"No se pudo enviar el pago","Could not update Wallet":"No se pudo actualizar el monedero","Create":"Crear","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Crea monedero {{requiredCopayers}}-de-{{totalCopayers}}","Create new wallet":"Crear un nuevo monedero","Create, join or import":"Crear, unirse o importar","Created by":"Creado por","Creating transaction":"Creando transacción","Creating Wallet...":"Creando monedero...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Comisión actual para esta política: {{fee.feePerKBUnit}}/kiB","Czech":"Checo","Date":"Fecha","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Descifrar un monedero de papel podría tomar alrededor de 5 minutos en este dispositivo. Por favor, sea paciente y mantenga la aplicación abierta.","Delete it and create a new one":"Borrar y crear uno nuevo","Delete Payment Proposal":"Eliminar Propuesta de Pago","Delete recovery phrase":"Eliminar frase de recuperación","Delete Recovery Phrase":"Eliminar Frase de Recuperación","Delete wallet":"Eliminar monedero","Delete Wallet":"Eliminar Monedero","Deleting Wallet...":"Eliminando Monedero...","Derivation Path":"Camino de derivación","Derivation Strategy":"Estrategia de derivación","Description":"Descripción","Details":"Detalles","Disabled":"Deshabilitado","Do not include private key":"No incluir la clave privada","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"¿No ve su idioma en Crowdin? Contáctese con el encargado del proyecto! Nos encantaría soportar su idioma.","Done":"Listo","Download":"Descargar","Economy":"Económico","Edit":"Editar","Edit comment":"Editar comentario","Edited by":"Editado por","Email for wallet notifications":"Correo electrónico para notificaciones del monedero","Email Notifications":"Notificaciones por Correo electrónico","Empty addresses limit reached. New addresses cannot be generated.":"Se ha alcanzado el límite de direcciones vacías. No se pueden generar nuevas direcciones.","Enable Coinbase Service":"Habilitar Coinbase","Enable Glidera Service":"Habilitar Glidera","Enable push notifications":"Activar notificaciones push","Encrypted export file saved":"El archivo cifrado se ha exportado y guardado","Enter the recovery phrase (BIP39)":"Introduzca la frase de recuperación (BIP39)","Enter your password":"Ingrese su contraseña","Enter your spending password":"Introduzca la contraseña para enviar","Error at Wallet Service":"Error en Wallet Service","Error creating wallet":"Error al crear monedero","Expired":"Expirada","Expires":"Expira","Export options":"Opciones de exportación","Export to file":"Exportar a archivo","Export Wallet":"Exportar Monedero","Exporting via QR not supported for this wallet":"Exportar vía código QR no es compatible para este monedero","Extended Public Keys":"Claves Públicas Extendidas","Extracting Wallet Information...":"Obteniendo Información del Monedero...","Failed to export":"Error al exportar","Failed to verify backup. Please check your information":"No se pudo comprobar la copia de seguridad. Por favor verifique su información","Family vacation funds":"Fondos para vacaciones en familia","Fee":"Comisión","Fetching Payment Information":"Obteniendo información del pago","File/Text":"Archivo/Texto","Finger Scan Failed":"Fallo en la verificación de la huella","Finish":"Finalizar","For audit purposes":"Para propósitos de auditoría","French":"Francés","From the destination device, go to Add wallet > Import wallet and scan this QR code":"Desde el dispositivo de destino, ir a Agregar monedero > Importar y escanear este código QR","Funds are locked by pending spend proposals":"Los fondos están bloqueados por propuestas de gastos pendientes","Funds found":"Fondos encontrados","Funds received":"Fondos Recibidos","Funds will be transferred to":"Los fondos serán transferidos a","Generate new address":"Generar nueva dirección","Generate QR Code":"Generar código QR","Generating .csv file...":"Generando archivo .csv...","German":"Alemán","Getting address for wallet {{selectedWalletName}} ...":"Obteniendo direcciones para el monedero {{selectedWalletName}} ...","Global preferences":"Preferencias globales","Hardware wallet":"Monedero de Hardware","Hardware Wallet":"Monedero Físico","Hide advanced options":"Ocultar opciones avanzadas","I affirm that I have read, understood, and agree with these terms.":"Confirmo haber leído, entendido y aceptado estos términos.","I AGREE. GET STARTED":"DE ACUERDO. COMENZAR","Import":"Importar","Import backup":"Importar copia de seguridad","Import wallet":"Importar monedero","Importing Wallet...":"Importando Monedero...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"En ningún caso los autores, empleados y afiliados de Bitpay, los titulares de derechos de autor, o BitPay, Inc. serán declarados responsables de los reclamos, daños o cualquier otra responsabilidad, ya sea en una acción de contrato, agravio o de otra manera, que surja fuera de la conexión con el software.","In order to verify your wallet backup, please type your password:":"Con el fin de verificar la copia de seguridad del monedero, por favor escriba su contraseña:","Incorrect address network":"Dirección de red incorrecta","Incorrect code format":"Formato de código incorrecto","Insufficient funds":"Fondos insuficientes","Insufficient funds for fee":"Fondos insuficientes para el pago de la comisión","Invalid":"Inválido","Invalid account number":"Número de cuenta inválido","Invalid address":"Dirección inválida","Invalid derivation path":"Camino de derivación no válido","Invitation to share a Copay Wallet":"Invitación para compartir un monedero de Copay","Italian":"Italiano","Japanese":"Japonés","John":"Juan","Join":"Unirse","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Únase a mi monedero Copay. Aquí esta el código de invitación: {{secret}}. Puedes descargar Copay a su teléfono o computadora desde https://copay.io","Join shared wallet":"Unirse a un monedero compartido","Joining Wallet...":"Uniéndose al monedero...","Key already associated with an existing wallet":"La clave ya esta asociada a un monedero existente","Label":"Etiqueta","Language":"Idioma","Last Wallet Addresses":"Últimas Direcciones del Monedero","Learn more about Copay backups":"Más información sobre copias de seguridad en Copay","Loading...":"Cargando...","locked by pending payments":"bloqueado por pagos pendientes","Locktime in effect. Please wait to create a new spend proposal":"Bloqueo temporal. Por favor espere para crear una nueva propuesta de gasto","Locktime in effect. Please wait to remove this spend proposal":"Bloqueo temporal. Por favor espere para eliminar esta propuesta de gasto","Make a payment to":"Hacer un pago a","Matches:":"Coincidencias:","me":"yo","Me":"Yo","Memo":"Nota","Merchant message":"Mensaje del negocio","Message":"Mensaje","Missing parameter":"Faltan parámetros","Missing private keys to sign":"Faltan las claves privadas para firmar","Moved":"Movido","Multiple recipients":"Varios destinatarios","My Bitcoin address":"Mi dirección Bitcoin","My contacts":"Mis contactos","My wallets":"Mis monederos","Need to do backup":"Necesita hacer una copias de seguridad","Network":"Red","Network connection error":"Error de conexión a la red","New Payment Proposal":"Nueva Propuesta de Pago","New Random Recovery Phrase":"Nueva frase de recuperación aleatoria","No hardware wallets supported on this device":"No hay monederos hardware compatibles con este dispositivo","No transactions yet":"Sin transacciones todavía","Normal":"Normal","Not authorized":"No autorizado","Not completed":"No completado","Not enough funds for fee":"No hay suficientes fondos para la comisión","Not valid":"No válido","Note":"Nota","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Nota: se excluyeron un total de {{amountAboveMaxSizeStr}}. El tamaño máximo permitido para una transacción se ha excedido","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Nota: se excluyeron un total de {{amountBelowFeeStr}}. Estos fondos provienen de UTXOs más pequeños que la tarifa de red suministrada.","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"Nota: Para importar un monedero de un software de tercero, por favor vaya a Añadir Monedero > Crear Monedero, y especificar la frase de recuperación allí.","Official English Disclaimer":"Renuncia oficial en inglés","OKAY":"LISTO","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"Una vez que ha copiado la frase de recuperación del monedero en un papel, es recomendable eliminarla del dispositivo.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Sólo las direcciones principales aparecen (no las usadas para el vuelto). Las direcciones de esta lista no fueron verificadas localmente en este momento.","Open Settings app":"Abrir Configuración de la Aplicación","optional":"opcional","Paper Wallet Private Key":"Clave privada del monedero de papel","Participants":"Participantes","Passphrase":"Contraseña","Password":"Contraseña","Password required. Make sure to enter your password in advanced options":"Contraseña necesaria. Asegúrese de introducir su contraseña en opciones avanzadas","Paste invitation here":"Pegar invitación aquí","Paste the backup plain text code":"Pegar copia de seguridad en texto plano","Paste your paper wallet private key here":"Pegar la clave privada del monedero aquí","Pasted from clipboard":"Pegado desde el portapapeles","Pay To":"Pagar A","Payment Accepted":"Pago Aceptado","Payment accepted, but not yet broadcasted":"Pago aceptado, pero aún no fue enviado","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Pago aceptado. Se transmitirá por Glidera. En caso de que haya un problema, puede eliminar la transacción 6 horas después de fue creada.","Payment details":"Detalles del pago","Payment expires":"Pago expira","Payment Proposal":"Propuesta de Pago","Payment Proposal Created":"Propuesta de Pago Creada","Payment Proposal Rejected":"Propuesta de Pago Rechazada","Payment Proposal Rejected by Copayer":"Propuesta de Pago Rechazada por Copayer","Payment Proposal Signed by Copayer":"Propuesta de Pago Firmada por Copayer","Payment Proposals":"Propuestas de Pago","Payment Protocol Invalid":"Protocolo de Pago Inválido","Payment Protocol not supported on Chrome App":"El protocolo de pago no está soportado en Chrome","Payment Rejected":"Pago Rechazado","Payment request":"Solicitud de pago","Payment Sent":"Pago Enviado","Payment to":"Pago a","Pending Confirmation":"Confirmación Pendiente","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Borrar permanentemente este monedero. ESTA ACCIÓN NO PUEDE SER REVERTIDA","Personal Wallet":"Monedero Personal","Please enter the recovery phrase":"Por favor ingrese la frase de recuperación","Please enter the required fields":"Por favor ingrese los campos requeridos","Please enter the wallet recovery phrase":"Por favor ingrese la frase de recuperación del monedero","Please tap the words in order to confirm your backup phrase is correctly written.":"Por favor presione las palabras para confirmar que su copia de seguridad está correctamente escrita.","Please upgrade Copay to perform this action":"Por favor actualice Copay para realizar esta acción","Please wait to be redirected...":"Por favor, espere a ser redirigido...","Please, select your backup file":"Por favor, seleccione el archivo de copia de seguridad","Polish":"Polaco","Preferences":"Preferencias","Preparing backup...":"Preparando copia de seguridad...","preparing...":"preparando...","Press again to exit":"Presione nuevamente para salir","Priority":"Prioritario","Private key is encrypted, cannot sign":"La clave privada esta encriptada, no puede firmar","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Notificaciones push para Copay están deshabilitadas. Habilitarla en la configuración de la aplicación.","QR Code":"Código QR","QR-Scanner":"Lector de QR","Receive":"Recibir","Received":"Recibido","Recipients":"Destinatarios","Recovery Phrase":"Frase de Recuperación","Recovery phrase deleted":"Frase de recuperación eliminada","Recreate":"Recrear","Recreating Wallet...":"Recreando Monedero...","Reject":"Rechazar","Release Information":"Información de la versión","Remove":"Eliminar","Repeat password":"Escriba nuevamente la contraseña","Repeat the password":"Repetir la contraseña","Repeat the spending password":"Repetir la contraseña para enviar","Request a specific amount":"Solicitar importe específico","Request Spending Password":"Solicitar contraseña para enviar","Required":"Requerido","Required number of signatures":"Número requerido de firmas","Retrieving inputs information":"Recuperando información de las entradas","Russian":"Ruso","Save":"Guardar","Scan addresses for funds":"Busca direcciones con fondos","Scan Fingerprint":"Lector de huella digital","Scan Finished":"Búsqueda Finalizada","Scan status finished with error":"La búsqueda finalizó con error","Scan Wallet Funds":"Buscar fondos del monedero","Scan your fingerprint please":"Por favor ingrese su huella digital","Scanning Wallet funds...":"Buscando fondos en el Monedero...","Search transactions":"Buscar transacciones","Search Transactions":"Buscar transacciones","Security preferences":"Preferencias de seguridad","See it on the blockchain":"Ver en la blockchain","Select a backup file":"Seleccionar el archivo de copia de seguridad","Select a wallet":"Seleccionar un monedero","Self-signed Certificate":"Certificado autofirmado","Send":"Enviar","Send addresses by email":"Enviar las direcciones por email","Send bitcoin":"Enviar bitcoin","Send by email":"Enviar por correo electrónico","Send Max":"Enviar máximo","Sending":"Enviando","Sending transaction":"Enviando transacción","Sent":"Enviado","Server response could not be verified":"La respuesta del servidor no se ha podido verificar","Session log":"Registro de sesión","SET":"ESTABLECER","Set default url":"Establecer URL predeterminada","Set up a password":"Configurar una contraseña","Set up a spending password":"Configurar contraseña para enviar","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Configurar notificaciones por correo electrónico podría debilitar su privacidad, si el proveedor de Wallet Service se ve comprometido. La información disponible para un atacante incluiría sus direcciones del monedero y su balance, pero no más.","Settings":"Configuración","Share address":"Compartir dirección","Share invitation":"Compartir invitación","Share this invitation with your copayers":"Compartir esta invitación con sus copayers","Share this wallet address to receive payments":"Compartir esta dirección del monedero para recibir pagos","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Compartir esta dirección para recibir pagos. Para proteger su privacidad, se generan nuevas direcciones automáticamente luego de recibir un pago.","Shared Wallet":"Monedero Compartido","Show advanced options":"Mostrar opciones avanzadas","Signatures rejected by server":"Firmas rechazadas por el servidor","Signing transaction":"Firmando transacción","Single Address Wallet":"Monedero de una sola dirección","Spanish":"Español","Specify Recovery Phrase...":"Especificar la frase de recuperación...","Spend proposal is not accepted":"La propuesta de gasto no se ha aceptado","Spend proposal not found":"La propuesta de gasto no se ha encontrado","Spending Password needed":"Se necesita la contraseña para enviar","Spending Passwords do not match":"Las contraseña para enviar no coinciden","Success":"Listo","Super Economy":"Súper Económico","Sweep paper wallet":"Importar monedero en papel","Sweep Wallet":"Importar Monedero","Sweeping Wallet...":"Leyendo el Monedero...","Tap and hold to show":"Tocar y mantener para mostrar","Tap to retry":"Toque para reintentar","Terms of Use":"Términos de Uso","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Los autores de los software, empleados y afiliados de Bitpay, los titulares de derechos de autor, y BitPay, Inc. no pueden recuperar sus claves privadas o contraseñas si se pierde o se olvida de ellos y no se puede garantizar la confirmación de la transacción, ya que no tienen control sobre la red Bitcoin.","The derivation path":"La ruta de derivación","The Ledger Chrome application is not installed":"La aplicación Ledger de Chrome no esta instalada","The password of the recovery phrase (if set)":"La contraseña de la frase de recuperación (si existe)","The payment was created but could not be completed. Please try again from home screen":"El pago fue creado pero no se pudo completar. Por favor intente nuevamente desde la pantalla de inicio","The payment was removed by creator":"El pago fue eliminado por el creador","The recovery phrase could require a password to be imported":"La frase de recuperación podría requerir una contraseña para ser importada","The request could not be understood by the server":"La solicitud no pudo ser comprendida por el servidor","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"El software no constituye una cuenta donde BitPay u otras terceras partes sirven como intermediarios financieros o custodios de su bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"El software que va a utilizar es un monedero digital de código abierto y multi-firmas.","The spend proposal is not pending":"La propuesta de gasto no esta pendiente","The wallet \"{{walletName}}\" was deleted":"El monedero \"{{walletName}}\" fue eliminado","The Wallet Recovery Phrase could require a password to be imported":"La frase de recuperación del monedero podría requerir una contraseña para ser importado","The wallet service URL":"URL de Wallet Service","There are no wallets to make this payment":"No dispone de monederos para realizar este pago","There is a new version of Copay. Please update":"Hay una nueva versión de Copay. Por favor actualizar","There is an error in the form":"Hay un error en el formulario","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"Esta frase de recuperación fue creada con una contraseña. Para recuperar este monedero, la frase de recuperación y la contraseña son necesarios.","This transaction has become invalid; possibly due to a double spend attempt.":"Esta transacción se ha invalidado; posiblemente debido a un intento de doble gasto.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Este monedero no esta registrado en el servidor de Bitcore Wallet Service (BWS). Debe recrearlo con la información local disponible.","Time":"Hora","To":"Para","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Para restaurar el monedero compartido {{index.m}}-{{index.n}} necesitará","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"En la máxima medida permitida por la ley, este software se proporciona \"tal cual está\" y no asume la responsabilidad ni ofrece garantías de ningún tipo, expresa o implícita, incluyendo, pero no limitado a las garantías comerciales, de conveniencia o a un propósito particular.","too long!":"¡demasiado largo!","Total Locked Balance":"Balance Total Bloqueado","Total number of copayers":"Número total de copayers","Touch ID Failed":"Falló Touch ID","Transaction":"Transacción","Transaction already broadcasted":"La transacción ya fue enviada","Transaction History":"Historial de Transacciones","Translation Credits":"Créditos de traducción","Translators":"Traductores","Try again":"Vuelva a intentarlo","Type the Recovery Phrase (usually 12 words)":"Escriba la frase de recuperación (normalmente 12 palabras)","Unconfirmed":"Sin confirmar","Unit":"Unidad","Unsent transactions":"Transacciones no enviadas","Updating transaction history. Please stand by.":"Actualizando el historial de transacciones. Por favor aguarde un momento.","Updating Wallet...":"Actualizando Monedero...","Use Unconfirmed Funds":"Utilizar los fondos sin confirmar","Validating recovery phrase...":"Validando la frase de recuperación...","Validating wallet integrity...":"Validación de integridad del monedero...","Version":"Versión","View":"Ver","Waiting for copayers":"Esperando a los demás copayers","Waiting for Ledger...":"Esperando a Ledger...","Waiting for Trezor...":"Esperando a Trezor...","Waiting...":"Esperando...","Wallet already exists":"El monedero ya existe","Wallet already in Copay":"El monedero ya existe en Copay","Wallet Configuration (m-n)":"Configuración del Monedero (m-n)","Wallet Export":"Exportar Monedero","Wallet Id":"Id del Monedero","Wallet incomplete and broken":"Monedero incompleto y roto","Wallet Information":"Información del Monedero","Wallet Invitation":"Invitación para unirse al monedero","Wallet Invitation is not valid!":"¡Invitación no válida!","Wallet is full":"El monedero está completo","Wallet is locked":"Monedero bloqueado","Wallet is not complete":"El monedero no esta completo","Wallet name":"Nombre del monedero","Wallet Name (at creation)":"Nombre del Monedero (al crear)","Wallet needs backup":"El monedero requiere copia de seguridad","Wallet Network":"Red del Monedero","Wallet not found":"Monedero no encontrado","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"El monedero no esta registrado en Wallet Service. Para volver a crear, utilice \"Crear Monedero\", \"Opciones avanzadas\" e ingrese la frase de recuperación","Wallet Preferences":"Preferencias del Monedero","Wallet Recovery Phrase":"Frase de recuperación del monedero","Wallet Recovery Phrase is invalid":"La frase de recuperación es inválida","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"La frase de recuperación del monedero no está disponible. Todavía puede exportar de avanzado > Exportar.","Wallet service not found":"Wallet Service no encontrado","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"ADVERTENCIA: Derivación de la clave no funciona en este dispositivo/monedero. Acciones no pueden realizarse en este monedero.","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"ADVERTENCIA: No incluir la clave privada permite verificar el saldo del monedero, historial de transacciones y crear propuestas de gastos. Sin embargo, no permite aprobar propuestas (firmar), así que los fondos no serán accesibles al exportar.","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"ADVERTENCIA: La contraseña no puede ser recuperada. Asegúrese de escribirlo en papel. El monedero no puede ser restaurado sin la contraseña.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"ADVERTENCIA: La clave privada de este monedero no está disponible. La exportación permite verificar el saldo del monedero, historial de transacciones y crear propuestas de gastos en la exportación. Sin embargo, no permite aprobar propuestas (firmar), así que los fondos no serán accesibles al exportar.","Warning: this transaction has unconfirmed inputs":"Advertencia: esta operación tiene entradas sin confirmar","WARNING: UNTRUSTED CERTIFICATE":"ADVERTENCIA: NO ES DE CONFIANZA EL CERTIFICADO","WARNING: Wallet not registered":"ADVERTENCIA: Monedero no registrado","Warning!":"¡Advertencia!","We reserve the right to modify this disclaimer from time to time.":"Nos reservamos el derecho a modificar el presente aviso legal de vez en cuando.","WELCOME TO COPAY":"BIENVENIDO A COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Mientras que el software ha experimentado pruebas en beta y aún sigue mejorando mediante la retroalimentación de la comunidad de desarrollador y usuarios de código abierto, no podemos garantizar que no habrá errores en el software.","Write your wallet recovery phrase":"Escriba la frase de recuperación del monedero","Wrong number of recovery words:":"Número incorrecto de palabras:","Wrong spending password":"Contraseña para enviar incorrecta","Yes":"Si","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Usted reconoce que el uso de este software es bajo tu propia responsabilidad y en cumplimiento con todas las leyes aplicables.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Usted es responsable de la custodia de sus contraseñas, pares de claves privadas, PIN y cualquier otro código que se utiliza para acceder al software.","You assume any and all risks associated with the use of the software.":"Usted asume todos los riesgos asociados con el uso del software.","You backed up your wallet. You can now restore this wallet at any time.":"Ya realizó una copia de seguridad de su monedero. Ahora puede restaurarlo en cualquier momento.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Con seguridad puede instalar su monedero en otro dispositivo y usarlo desde varios dispositivos al mismo tiempo.","You do not have any wallet":"No tienes ningún monedero","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"Necesita la frase de recuperación para restaurar su monedero personal. Anótela y guárdela en algún lugar seguro.","Your nickname":"Sobrenombre","Your password":"Contraseña","Your spending password":"Contraseña para enviar","Your wallet has been imported correctly":"El monedero se ha importado correctamente","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"La clave del monedero se cifrará. La contraseña para enviar no puede ser recuperada. Asegúrese de escribirla","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Su frase de recuperación del monedero y el acceso al servidor que coordina la creación del monedero inicial. Aún necesita de {{index.m}} claves para enviar."}); - gettextCatalog.setStrings('fr', {"(possible double spend)":"(double dépense possible)","(Trusted)":"(Fiable)","[Balance Hidden]":"[Solde masqué]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} seront déduits pour les frais de réseau Bitcoin","{{feeRateStr}} of the transaction":"{{feeRateStr}} de la transaction","{{index.m}}-of-{{index.n}}":"{{index.m}}-sur-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} de plus","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} transactions téléchargées","{{item.m}}-of-{{item.n}}":"{{item.m}}-sur-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Une proposition de paiement peut être supprimée si vous en êtes le créateur et qu'aucun des autres copayers n'a signé, ou si 24 heures sont passées depuis la création de la proposition.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"SI VOUS PERDEZ L'ACCÈS À VOTRE PORTEFEUILLE COPAY OU À VOS CLÉS PRIVÉES CHIFFRÉES ET QUE VOUS N'AVEZ PAS ENTREPOSÉ SÉPARÉMENT UNE SAUVEGARDE DE VOTRE PORTEFEUILLE ET LES MOTS DE PASSE CORRESPONDANT, VOUS RECONNAISSEZ ET ACCEPTEZ QUE LES BITCOINS QUE VOUS AVEZ ASSOCIÉ À CE PORTEFEUILLE COPAY DEVIENNENT INACCESSIBLES.","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"OU 1 fichier d'exportation de portefeuille et le quorum restant en phrases de récupération de portefeuille (ex. dans un portefeuille 3-5 : 1 fichier d'exportation du portefeuille + 2 phrases de récupération du portefeuille de n'importe quels autres copayers).","OR the wallet recovery phrase of all copayers in the wallet":"OU la phrase de récupération de portefeuille de tous les copayers du portefeuille","OR the wallet recovery phrases of all copayers in the wallet":"OU les phrases de récupération de portefeuille de tous les copayers du portefeuille","A multisignature bitcoin wallet":"Un portefeuille bitcoin multi-signatures","About Copay":"À propos de Copay","Accept":"Accepter","Account":"Compte","Account Number":"Numéro de compte","Activity":"Activité","Add a new entry":"Ajouter une nouvelle entrée","Add a Password":"Ajouter un mot de passe","Add an optional password to secure the recovery phrase":"Ajouter un mot de passe optionnel pour sécuriser la phrase de récupération","Add comment":"Ajouter un commentaire","Add wallet":"Ajouter portefeuille","Address":"Adresse","Address Type":"Type d'adresse","Advanced":"Paramètres avancés","Alias":"Alias","Alias for {{index.walletName}}":"Alias pour {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Toutes les contributions à la traduction de Copay sont les bienvenues. Inscrivez-vous sur crowdin.com et rejoignez le projet Copay sur","All transaction requests are irreversible.":"Toutes les transactions sont irréversibles.","Alternative Currency":"Devise alternative","Amount":"Montant","Amount below minimum allowed":"Montant en dessous du minimum autorisé","Amount in":"Montant en","Are you sure you want to delete the recovery phrase?":"Êtes-vous sûr(e) de vouloir supprimer la phrase de récupération ?","Are you sure you want to delete this wallet?":"Êtes-vous certain(e) de vouloir supprimer ce portefeuille ?","Auditable":"Vérifiable","Available Balance":"Solde disponible","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Temps de confirmation moyen : {{fee.nbBlocks * 10}} minutes","Back":"Retour","Backup":"Sauvegarder","Backup failed":"La sauvegarde a échoué","Backup Needed":"Sauvegarde requise","Backup now":"Sauvegarder","Bad wallet invitation":"Mauvaise invitation de portefeuille","Balance By Address":"Solde par adresse","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Avant de recevoir des fonds, vous devez sauvegarder votre portefeuille. Si vous perdez cet appareil, vos fonds seront irrécupérables sans une sauvegarde.","BETA: Android Key Derivation Test:":"BETA: Android Key Derivation Test:","BIP32 path for address derivation":"Chemin BIP32 pour la dérivation de l'adresse","Bitcoin address":"Adresse Bitcoin","Bitcoin Network Fee Policy":"Frais de réseau","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Les transactions Bitcoin peuvent inclure des frais prélevés par les mineurs du réseau. Plus les frais sont importants, et plus un mineur sera incité à inclure cette transaction dans un bloc. Les frais actuels sont déterminés en fonction de la charge du réseau et du choix sélectionné.","Bitcoin URI is NOT valid!":"L'URI Bitcoin n'est pas valide !","Broadcast Payment":"Diffuser le paiement","Broadcasting transaction":"Diffusion de la transaction","Browser unsupported":"Navigateur non supporté","Buy and Sell":"Acheter et Vendre","Calculating fee":"Calcul des frais","Cancel":"Annuler","Cancel and delete the wallet":"Annuler et supprimer le portefeuille","Cannot create transaction. Insufficient funds":"Impossible de créer la transaction. Fonds insuffisants","Cannot join the same wallet more that once":"Impossible de rejoindre le même portefeuille plus d'une fois","Cannot sign: The payment request has expired":"Impossible de signer : la demande de paiement a expiré","Certified by":"Certifié par","Changing wallet alias only affects the local wallet name.":"La modification d'un alias de portefeuille affecte uniquement le nom du portefeuille local.","Chinese":"Chinois","Choose a backup file from your computer":"Choisissez un fichier de sauvegarde depuis votre ordinateur","Clear cache":"Vider le cache","Close":"Fermer","Color":"Couleur","Comment":"Commentaire","Commit hash":"Commit hash","Confirm":"Confirmer","Confirm your wallet recovery phrase":"Confirmez votre phrase de récupération du portefeuille","Confirmations":"Confirmations","Congratulations!":"Félicitations !","Connecting to Coinbase...":"Connexion à Coinbase...","Connecting to Glidera...":"Connexion à Glidera...","Connection reset by peer":"Connexion réinitialisée par un pair","Continue":"Continuer","Copayer already in this wallet":"Copayer déjà dans ce portefeuille","Copayer already voted on this spend proposal":"Le Copayer a déjà voté pour cette proposition de dépense","Copayer data mismatch":"Les données Copayer ne correspondent pas","Copayers":"Copayers","Copied to clipboard":"Copié dans le presse-papier","Copy this text as it is to a safe place (notepad or email)":"Copiez ce texte présenté tel quel vers un endroit sûr (bloc-notes ou e-mail)","Copy to clipboard":"Copier dans le presse-papier","Could not access the wallet at the server. Please check:":"Impossible d'accéder au portefeuille via le serveur. Veuillez vérifier :","Could not access wallet":"Impossible d’accéder au portefeuille","Could not access Wallet Service: Not found":"Impossible d'accéder au Wallet Service : Introuvable","Could not broadcast payment":"Impossible de diffuser le paiement","Could not build transaction":"Impossible de créer la transaction","Could not create address":"Impossible de créer l'adresse","Could not create payment proposal":"Impossible de créer la proposition de paiement","Could not create using the specified extended private key":"Impossible de créer en utilisant la clé privée étendue spécifiée","Could not create using the specified extended public key":"Impossible de créer en utilisant la clé publique étendue spécifiée","Could not create: Invalid wallet recovery phrase":"Impossible de créer : Phrase de récupération du portefeuille invalide","Could not decrypt file, check your password":"Impossible de déchiffrer le fichier, vérifiez votre mot de passe","Could not delete payment proposal":"Impossible de supprimer la proposition de paiement","Could not fetch payment information":"Impossible de récupérer les informations de paiement","Could not get fee value":"Impossible d'obtenir la valeur des frais","Could not import":"Impossible d'importer","Could not import. Check input file and spending password":"Impossible d'importer. Vérifiez le fichier d'entrée et le code de dépenses","Could not join wallet":"Impossible de rejoindre le portefeuille","Could not recognize a valid Bitcoin QR Code":"Impossible de reconnaître un code QR Bitcoin valide","Could not reject payment":"Impossible de rejeter le paiement","Could not send payment":"Impossible d'envoyer le paiement","Could not update Wallet":"Impossible de mettre à jour le portefeuille","Create":"Créer","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Créer un portefeuille {{requiredCopayers}}-sur-{{totalCopayers}}","Create new wallet":"Créer","Create, join or import":"Créer, rejoindre ou importer","Created by":"Créée par","Creating transaction":"Création de la transaction","Creating Wallet...":"Création du portefeuille...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Frais actuels pour ce choix : {{fee.feePerKBUnit}}/kiB","Czech":"Tchèque","Date":"Date","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Le déchiffrement d'un portefeuille de papier peut prendre environ 5 minutes sur cet appareil. Veuillez être patient et gardez l'application ouverte.","Delete it and create a new one":"Le supprimer et en créer un nouveau","Delete Payment Proposal":"Supprimer la proposition de paiement","Delete recovery phrase":"Supprimer la phrase de récupération","Delete Recovery Phrase":"Supprimer la phrase de récupération","Delete wallet":"Supprimer le portefeuille","Delete Wallet":"Supprimer le portefeuille","Deleting Wallet...":"Suppression du portefeuille...","Derivation Path":"Chemin de dérivation","Derivation Strategy":"Stratégie de dérivation","Description":"Description","Details":"Détails","Disabled":"Désactivé","Do not include private key":"Ne pas inclure la clé privée","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Vous ne voyez pas votre langue sur Crowdin ? Contactez le propriétaire sur Crowdin ! Nous serions ravis de prendre en charge votre langue.","Done":"Terminé","Download":"Télécharger","Economy":"Faibles","Edit":"Modifier","Edit comment":"Modifier le commentaire","Edited by":"Modifié par","Email for wallet notifications":"E-mail pour les notifications de portefeuille","Email Notifications":"Notifications e-mail","Empty addresses limit reached. New addresses cannot be generated.":"La limite d'adresses vides a été atteinte. Les nouvelles adresses ne peuvent plus être générées.","Enable Coinbase Service":"Activer le service Coinbase","Enable Glidera Service":"Activer le service Glidera","Enable push notifications":"Autoriser les notifications push","Encrypted export file saved":"Le fichier d'exportation chiffré a été enregistré","Enter the recovery phrase (BIP39)":"Saisissez la phrase de récupération (BIP39)","Enter your password":"Écrivez votre mot de passe","Enter your spending password":"Saisissez votre code de dépenses","Error at Wallet Service":"Erreur au niveau de Wallet Service","Error creating wallet":"Erreur de création du portefeuille","Expired":"Expiré","Expires":"Expire","Export options":"Options d'exportation","Export to file":"Exporter vers un fichier","Export Wallet":"Exporter le portefeuille","Exporting via QR not supported for this wallet":"L'exportation via QR n'est pas supportée pour ce portefeuille","Extended Public Keys":"Clés publiques étendues","Extracting Wallet Information...":"Extraction des informations du portefeuille...","Failed to export":"Impossible d'exporter","Failed to verify backup. Please check your information":"Impossible de vérifier la sauvegarde. Veuillez vérifier vos informations","Family vacation funds":"Fonds pour les vacances familiales","Fee":"Frais","Fetching Payment Information":"Récupération des informations de paiement","File/Text":"Fichier / Texte","Finger Scan Failed":"La numérisation digitale a échoué","Finish":"Terminer","For audit purposes":"À des fins de vérification","French":"Français","From the destination device, go to Add wallet > Import wallet and scan this QR code":"Depuis le périphérique de destination, allez sur « Ajouter portefeuille » > « Importer » et numérisez ce code QR","Funds are locked by pending spend proposals":"Les fonds sont verrouillés par des propositions de dépenses en attente","Funds found":"Fonds trouvés","Funds received":"Fonds reçus","Funds will be transferred to":"Les fonds seront transférés à","Generate new address":"Générer une nouvelle adresse","Generate QR Code":"Générer un code QR","Generating .csv file...":"Génération du fichier .csv...","German":"Allemand","Getting address for wallet {{selectedWalletName}} ...":"Obtention d'une adresse pour le portefeuille {{selectedWalletName}} ...","Global preferences":"Préférences globales","Hardware wallet":"Portefeuille matériel","Hardware Wallet":"Portefeuille matériel","Hide advanced options":"Masquer les options avancées","I affirm that I have read, understood, and agree with these terms.":"Je confirme que j'ai lu, compris et suis d'accord avec ces conditions.","I AGREE. GET STARTED":"J’ACCEPTE. COMMENCER","Import":"Importer","Import backup":"Importer la sauvegarde","Import wallet":"Importer","Importing Wallet...":"Importation du portefeuille...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"En aucun cas les auteurs du logiciel, employés et sociétés affiliés de Bitpay, détenteurs de droits d'auteur, ou BitPay, Inc. ne peuvent être tenus responsables de toute réclamation, dommages ou autre responsabilité, que ce soit dans une action contractuelle, délictuelle ou autre, découlant ou en étant en connexion avec le logiciel.","In order to verify your wallet backup, please type your password:":"Afin de vérifier votre sauvegarde du portefeuille, veuillez saisir votre mot de passe :","Incorrect address network":"Adresse réseau incorrecte","Incorrect code format":"Format du code incorrect","Insufficient funds":"Fonds insuffisants","Insufficient funds for fee":"Fonds insuffisants pour les frais","Invalid":"Invalide","Invalid account number":"Numéro de compte invalide","Invalid address":"Adresse invalide","Invalid derivation path":"Chemin de dérivation invalide","Invitation to share a Copay Wallet":"Invitation pour partager un portefeuille Copay","Italian":"Italien","Japanese":"Japonais","John":"John","Join":"Rejoindre","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Rejoignez mon portefeuille Copay. Voici le code d'invitation : {{secret}} Vous pouvez télécharger Copay pour votre téléphone ou pour votre ordinateur sur https://copay.io","Join shared wallet":"Rejoindre","Joining Wallet...":"Connexion au portefeuille...","Key already associated with an existing wallet":"La clé est déjà associée avec un portefeuille existant","Label":"Étiquette","Language":"Langue","Last Wallet Addresses":"Dernières adresses du portefeuille","Learn more about Copay backups":"En savoir plus sur les sauvegardes de Copay","Loading...":"Chargement...","locked by pending payments":"verrouillés par les paiements en attente","Locktime in effect. Please wait to create a new spend proposal":"Locktime effectif. Veuillez patienter pour créer une nouvelle proposition de dépense","Locktime in effect. Please wait to remove this spend proposal":"Locktime effectif. Veuillez patienter pour supprimer cette proposition de dépense","Make a payment to":"Faire un paiement à","Matches:":"Correspondances :","me":"moi","Me":"Moi","Memo":"Note","Merchant message":"Message marchand","Message":"Message","Missing parameter":"Paramètre manquant","Missing private keys to sign":"Clés privées manquantes pour signer","Moved":"Déplacés","Multiple recipients":"Plusieurs destinataires","My Bitcoin address":"Mon adresse Bitcoin","My contacts":"Mes contacts","My wallets":"Mes portefeuilles","Need to do backup":"Vous devez faire une sauvegarde","Network":"Réseau","Network connection error":"Erreur de connexion réseau","New Payment Proposal":"Nouvelle proposition de paiement","New Random Recovery Phrase":"Nouvelle phrase de récupération aléatoire","No hardware wallets supported on this device":"Aucun portefeuille matériel pris en charge sur cet appareil","No transactions yet":"Aucune transaction","Normal":"Normaux","Not authorized":"Non autorisé","Not completed":"Inachevée","Not enough funds for fee":"Pas assez de fonds pour les frais","Not valid":"Invalide","Note":"Note","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Note : un total de {{amountAboveMaxSizeStr}} a été exclu. La taille maximale autorisée d'une transaction a été dépassée","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Note : un total de {{amountBelowFeeStr}} a été exclu. Ces fonds proviennent d'une entrée plus petite que les frais de réseau prévus.","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"Remarque : Pour importer un portefeuille d’un autre logiciel que Copay, veuillez aller dans « Ajouter portefeuille » > « Créer » et spécifier la phrase de récupération.","Official English Disclaimer":"Clause de non-responsabilité anglaise officielle","OKAY":"OK","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"Une fois que vous avez écrit votre phrase de récupération du portefeuille, il est recommandé de la supprimer de cet appareil.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Seules les adresses principales (pas celles de change) sont indiquées. Les adresses sur cette liste n'ont pas été vérifiées localement à ce moment.","Open Settings app":"Ouvrir les paramètres de l'appli","optional":"optionnelle","Paper Wallet Private Key":"Clé privée du portefeuille de papier","Participants":"Participants","Passphrase":"Phrase de passe","Password":"Mot de passe","Password required. Make sure to enter your password in advanced options":"Mot de passe requis. Veuillez saisir votre mot de passe dans les options avancées","Paste invitation here":"Collez l'invitation ici","Paste the backup plain text code":"Collez le code texte de sauvegarde","Paste your paper wallet private key here":"Collez ici votre clé privée du portefeuille de papier","Pasted from clipboard":"Collé depuis le presse-papier","Pay To":"Payer à","Payment Accepted":"Paiement accepté","Payment accepted, but not yet broadcasted":"Paiement accepté, mais pas encore diffusé","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Paiement accepté. Il sera diffusé par Glidera. Dans le cas où il y a un problème, il peut être supprimé 6 heures après avoir été créé.","Payment details":"Détails du paiement","Payment expires":"Paiement expiré","Payment Proposal":"Proposition de paiement","Payment Proposal Created":"Proposition de paiement créée","Payment Proposal Rejected":"Proposition de paiement rejetée","Payment Proposal Rejected by Copayer":"Proposition de paiement rejetée par les Copayer","Payment Proposal Signed by Copayer":"Proposition de paiement signée par les Copayers","Payment Proposals":"Propositions de paiement","Payment Protocol Invalid":"Protocole de paiement invalide","Payment Protocol not supported on Chrome App":"Le protocole de paiement n'est pas supporté sur l'application Chrome","Payment Rejected":"Paiement rejeté","Payment request":"Demande de paiement","Payment Sent":"Paiement envoyé","Payment to":"Paiement à","Pending Confirmation":"Confirmation en attente","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Supprimer définitivement ce portefeuille.
CETTE ACTION NE PEUT PAS ÊTRE ANNULÉE","Personal Wallet":"Portefeuille personnel","Please enter the recovery phrase":"Veuillez saisir la phrase de récupération","Please enter the required fields":"Veuillez saisir les champs requis","Please enter the wallet recovery phrase":"Veuillez saisir la phrase de récupération du portefeuille","Please tap the words in order to confirm your backup phrase is correctly written.":"Veuillez sélectionner les mots afin de confirmer que votre phrase de sauvegarde est correctement écrite.","Please upgrade Copay to perform this action":"Veuillez mettre à jour Copay pour effectuer cette action","Please wait to be redirected...":"Veuillez attendre la redirection...","Please, select your backup file":"Veuillez sélectionner votre fichier de sauvegarde","Polish":"Polonais","Preferences":"Préférences","Preparing backup...":"Préparation de la sauvegarde...","preparing...":"préparation...","Press again to exit":"Appuyez de nouveau pour quitter","Priority":"Importants","Private key is encrypted, cannot sign":"La clé privée est chiffrée, impossible de signer","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Les notifications push de Copay sont actuellement désactivées. Activez-les dans les paramètres de l'appli.","QR Code":"Code QR","QR-Scanner":"QR-Scanner","Receive":"Recevoir","Received":"Reçus","Recipients":"Destinataire(s)","Recovery Phrase":"Phrase de récupération","Recovery phrase deleted":"Phrase de récupération supprimée","Recreate":"Recréer","Recreating Wallet...":"Recréation du portefeuille...","Reject":"Rejeter","Release Information":"Informations de version","Remove":"Supprimer","Repeat password":"Confirmez le mot de passe","Repeat the password":"Confirmez le mot de passe","Repeat the spending password":"Confirmez le code de dépenses","Request a specific amount":"Demander un montant précis","Request Spending Password":"Demander un code de dépenses","Required":"Requis","Required number of signatures":"Nombre requis de signatures","Retrieving inputs information":"Récupération des informations d'entrée","Russian":"Russe","Save":"Valider","Scan addresses for funds":"Analyser les adresses pour des fonds","Scan Fingerprint":"Scanner l'empreinte digitale","Scan Finished":"Analyse terminée","Scan status finished with error":"Analyse terminée avec des erreurs","Scan Wallet Funds":"Analyser les fonds du portefeuille","Scan your fingerprint please":"Veuillez scanner votre empreinte digitale","Scanning Wallet funds...":"Analyse des fonds du portefeuille...","Search transactions":"Rechercher des transactions","Search Transactions":"Rechercher des transactions","Security preferences":"Préférences de sécurité","See it on the blockchain":"Voir sur la blockchain","Select a backup file":"Sélectionner un fichier de sauvegarde","Select a wallet":"Sélectionner un portefeuille","Self-signed Certificate":"Certificat auto-signé","Send":"Envoyer","Send addresses by email":"Envoyer les adresses par e-mail","Send bitcoin":"Envoyer les bitcoins","Send by email":"Envoyer par e-mail","Send Max":"Envoyer le maximum","Sending":"Envoi","Sending transaction":"Envoi de la transaction","Sent":"Envoyés","Server response could not be verified":"La réponse du serveur n'a pas pu être vérifiée","Session log":"Journal de session","SET":"DÉFINIR","Set default url":"Définir l'url par défaut","Set up a password":"Spécifiez un mot de passe","Set up a spending password":"Configurer un code de dépenses","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Configurer des notifications e-mail peut affaiblir votre anonymat si le fournisseur du service de portefeuille est compromis. Les informations disponibles à un attaquant incluent les adresses de votre portefeuille et leurs soldes, mais rien de plus.","Settings":"Paramètres","Share address":"Partager l'adresse","Share invitation":"Partager l'invitation","Share this invitation with your copayers":"Partagez cette invitation avec vos copayers","Share this wallet address to receive payments":"Partagez cette adresse de portefeuille pour recevoir des paiements","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Partagez cette adresse de portefeuille pour recevoir des paiements. Pour protéger votre anonymat, de nouvelles adresses sont générées automatiquement une fois que vous les utilisez.","Shared Wallet":"Portefeuille partagé","Show advanced options":"Afficher les options avancées","Signatures rejected by server":"Signatures rejetées par le serveur","Signing transaction":"Signature de la transaction","Single Address Wallet":"Portefeuille d'adresse unique","Spanish":"Espagnol","Specify Recovery Phrase...":"Spécifier la phrase de récupération...","Spend proposal is not accepted":"La proposition de dépense n'est pas acceptée","Spend proposal not found":"Propostion de dépense introuvable","Spending Password needed":"Code de dépenses requis","Spending Passwords do not match":"Les codes de dépenses ne correspondent pas","Success":"Succès","Super Economy":"Infimes","Sweep paper wallet":"Balayer un portefeuille de papier","Sweep Wallet":"Balayer un portefeuille","Sweeping Wallet...":"Balayage du portefeuille...","Tap and hold to show":"Appuyez et maintenez pour afficher","Tap to retry":"Tapotez pour réessayer","Terms of Use":"Conditions d'utilisation","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Les auteurs de ce logiciel, employés et sociétés affiliés à BitPay, détenteurs de droits d'auteur, et BitPay, Inc. ne peuvent pas récupérer vos clés privées ou mots de passe si vous les perdez et ne peuvent pas garantir la confirmation des transactions étant donné qu'ils n'ont pas de contrôle sur le réseau Bitcoin.","The derivation path":"Le chemin de dérivation","The Ledger Chrome application is not installed":"L'application Ledger pour Chrome n'est pas installée","The password of the recovery phrase (if set)":"Le mot de passe de la phrase de récupération (si configuré)","The payment was created but could not be completed. Please try again from home screen":"Le paiement a été créé mais n'a pas pu être achevé. Veuillez réessayer depuis l'écran d'accueil","The payment was removed by creator":"Le paiement a été supprimé par le créateur","The recovery phrase could require a password to be imported":"La phrase de récupération pourrait demander un mot de passe pour être importée","The request could not be understood by the server":"La demande n'a pas été comprise par le serveur","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Le logiciel ne constitue pas un compte où BitPay, ou des tiers, agissent comme des intermédiaires financiers ou dépositaires de vos bitcoins.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Le logiciel que vous êtes sur le point d'utiliser fonctionne comme un portefeuille numérique gratuit, open source et multi-signatures.","The spend proposal is not pending":"La proposition de dépense n'est pas en attente","The wallet \"{{walletName}}\" was deleted":"Le portefeuille \"{{walletName}}\" a été supprimé","The Wallet Recovery Phrase could require a password to be imported":"La phrase de récupération du portefeuille pourrait demander un mot de passe pour être importée","The wallet service URL":"L’URL du service de portefeuille","There are no wallets to make this payment":"Il n'y a pas de portefeuilles pour faire ce paiement","There is a new version of Copay. Please update":"Il y a une nouvelle version de Copay. Veuillez mettre à jour","There is an error in the form":"Il y a une erreur dans la forme","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"Cette phrase de récupération a été créée avec un mot de passe. Pour récupérer ce portefeuille, la phrase de récupération et le mot de passe sont requis.","This transaction has become invalid; possibly due to a double spend attempt.":"Cette transaction est devenue invalide ; il s'agit peut-être d'une tentative de double dépense.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Ce portefeuille n'est pas enregistré dans le Bitcore Wallet Service (BWS) donné. Vous pouvez le recréer depuis l'information locale.","Time":"Ancienneté","To":"À","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Pour restaurer ce portefeuille partagé {{index.m}}-{{index.n}} vous aurez besoin de","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"Dans toute la mesure permise par la loi, ce logiciel est fourni “tel quel” et aucune représentation ou garantie ne peut être faite de toute nature, expresse ou implicite, y compris, mais sans s'y limiter, aux garanties de qualité marchande, à la conformité ou à un usage particulier et absent de contrefaçon.","too long!":"trop long !","Total Locked Balance":"Solde verrouillé total","Total number of copayers":"Nombre total de copayers","Touch ID Failed":"Touch ID a échoué","Transaction":"Transaction","Transaction already broadcasted":"Transaction déjà diffusée","Transaction History":"Historique des transactions","Translation Credits":"Crédits de traduction","Translators":"Traducteurs","Try again":"Réessayer","Type the Recovery Phrase (usually 12 words)":"Saisissez la phrase de récupération (généralement 12 mots)","Unconfirmed":"Non confirmée","Unit":"Unité","Unsent transactions":"Transactions non envoyées","Updating transaction history. Please stand by.":"Mise à jour de l'historique des transactions. Veuillez patienter.","Updating Wallet...":"Mise à jour du portefeuille...","Use Unconfirmed Funds":"Utiliser les fonds non confirmés","Validating recovery phrase...":"Validation de la phrase de récupération...","Validating wallet integrity...":"Validation de l’intégrité du portefeuille...","Version":"Version","View":"Voir","Waiting for copayers":"Attente des copayers","Waiting for Ledger...":"En attente de Ledger...","Waiting for Trezor...":"En attente de Trezor...","Waiting...":"Attente...","Wallet already exists":"Le portefeuille existe déjà","Wallet already in Copay":"Le portefeuille existe déjà dans Copay","Wallet Configuration (m-n)":"Configuration du portefeuille (m-n)","Wallet Export":"Exportation du portefeuille","Wallet Id":"Id du portefeuille","Wallet incomplete and broken":"Portefeuille incomplet et cassé ","Wallet Information":"Informations du portefeuille","Wallet Invitation":"Invitation de portefeuille","Wallet Invitation is not valid!":"L'invitation de portefeuille n'est pas valide !","Wallet is full":"Le portefeuille est plein","Wallet is locked":"Le portefeuille est verrouillé","Wallet is not complete":"Le portefeuille n'est pas complet","Wallet name":"Nom du portefeuille","Wallet Name (at creation)":"Nom du portefeuille (à la création)","Wallet needs backup":"Le portefeuille a besoin d'une sauvegarde","Wallet Network":"Réseau du portefeuille","Wallet not found":"Portefeuille introuvable","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"Le portefeuille n'est pas enregistré au Wallet Service. Vous pouvez le recréer depuis « Créer » en utilisant les « Options avancées » pour configurer votre phrase de récupération","Wallet Preferences":"Préférences du portefeuille","Wallet Recovery Phrase":"Phrase de récupération","Wallet Recovery Phrase is invalid":"La phrase de récupération du portefeuille est invalide","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"La phrase de récupération du portefeuille n'est pas disponible. Vous pouvez toujours l'exporter depuis les « Paramètres avancés » > « Exporter ».","Wallet service not found":"Wallet Service introuvable","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"ATTENTION : La dérivation de la clé ne fonctionne pas sur cet appareil / portefeuille. Impossible d’effectuer des actions sur ce portefeuille.","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"ATTENTION : Ne pas inclure la clé privée permet de vérifier le solde du portefeuille, l'historique des transactions, et de créer des demandes de dépenses depuis le fichier exporté. Cependant, cela ne permet pas d'approuver (signer) les propositions et les fonds ne seront pas accessibles depuis le fichier exporté.","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"ATTENTION : Le mot de passe ne peut pas être récupéré. Veillez l'écrire sur papier. Le portefeuille ne peut pas être restauré sans le mot de passe.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"ATTENTION : La clé privée de ce portefeuille n'est pas disponible. L'exportation permet de vérifier le solde du portefeuille, l'historique des transactions, et de créer des propositions de dépenses depuis le fichier exporté. Cependant, cela ne permet pas d'approuver (signer) les propositions et les fonds ne seront pas accessibles depuis le fichier exporté.","Warning: this transaction has unconfirmed inputs":"ATTENTION : Cette transaction a des entrées non confirmées","WARNING: UNTRUSTED CERTIFICATE":"ATTENTION : CERTIFICAT NON APPROUVÉ","WARNING: Wallet not registered":"ATTENTION : Portefeuille non enregistré","Warning!":"Attention !","We reserve the right to modify this disclaimer from time to time.":"Nous nous réservons le droit de modifier cette clause de non-responsabilité de temps à autre.","WELCOME TO COPAY":"BIENVENUE SUR COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Bien que le logiciel ait subi des tests bêta et continue d'être amélioré par les retours d'utilisateurs et de développeurs de la communauté open source, nous ne pouvons pas garantir qu'il n'y aura plus de bugs dans le logiciel.","Write your wallet recovery phrase":"Écrivez votre phrase de récupération du portefeuille","Wrong number of recovery words:":"Nombre incorrect de mots de récupération :","Wrong spending password":"Code de dépenses incorrect","Yes":"Oui","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Vous reconnaissez que votre utilisation de ce logiciel est à votre propre discrétion et est en conformité avec toutes les lois applicables.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Vous êtes responsable de la sauvegarde de vos mots de passe, paires de clés privées, codes PIN et autres codes que vous utilisez pour accéder au logiciel.","You assume any and all risks associated with the use of the software.":"Vous assumez tous les risques associés à l'utilisation du logiciel.","You backed up your wallet. You can now restore this wallet at any time.":"Vous avez sauvegardé votre portefeuille. Vous pouvez maintenant restaurer ce portefeuille à n'importe quel moment.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Vous pouvez installer en toute sécurité votre portefeuille sur un autre appareil et l'utiliser à partir de plusieurs périphériques en même temps.","You do not have any wallet":"Vous n'avez aucun portefeuille","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"Vous avez besoin de la phrase de récupération du portefeuille pour restaurer ce portefeuille personnel. Notez-la et conservez-la dans un endroit sûr.","Your nickname":"Votre surnom","Your password":"Votre mot de passe","Your spending password":"Votre code de dépenses","Your wallet has been imported correctly":"Votre portefeuille a été correctement importé","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"La clé de votre portefeuille sera chiffrée. Le code de dépenses ne peut pas être récupéré. N'oubliez pas de l'écrire","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Votre phrase de récupération du portefeuille et l'accès au serveur qui a coordonné la création du portefeuille initial. Vous avez encore besoin de {{index.m}} clés pour dépenser."}); - gettextCatalog.setStrings('it', {"(possible double spend)":"(possibile doppia spesa)","(Trusted)":"(Fidato)","[Balance Hidden]":"[Fondi Nascosti]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} verranno detratti come commissione del network","{{feeRateStr}} of the transaction":"{{feeRateStr}} della transazione","{{index.m}}-of-{{index.n}}":"{{index.m}}-di-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} altre","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} transazioni scaricate","{{item.m}}-of-{{item.n}}":"{{item.m}}-di-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Una proposta di pagamento può essere eliminata se 1) Tu sei il creatore e nessun altro copayer ha firmato, oppure 2) Sono passate 24 ore da quando la proposta e' stata creata.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"Se perdi l'accesso al tuo portafoglio COPAY o tuo crittografato chiavi PRIVATE e non hai archiviato separatamente una copia di BACKUP del vostro portafoglio e la corrispondente PASSWORD, tu riconosci e accetti che qualsiasi BITCOIN associato con quel portafoglio COPAY diventerà inaccessibile.","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"O 1 file di portafoglio esportato e il restante quorum di frasi di recupero portafoglio (ad esempio in un 3-5 portafogli: 1 file di portafoglio esportato + 2 frasi di recupero portafoglio di qualsiasi degli altri copayers).","OR the wallet recovery phrase of all copayers in the wallet":"O la frase di recupero di portafoglio di tutti i copayers nel portafoglio","OR the wallet recovery phrases of all copayers in the wallet":"O le frasi di recupero di portafoglio di tutti i copayers nel portafoglio","A multisignature bitcoin wallet":"Un portafoglio bitcoin multifirma","About Copay":"Circa Copay","Accept":"Accetta","Account":"Conto","Account Number":"Numero del Conto","Activity":"Attività","Add a new entry":"Aggiungi una nuova voce","Add a Password":"Aggiungi una Password","Add an optional password to secure the recovery phrase":"Aggiungere una password facoltativa per proteggere la frase di recupero","Add comment":"Aggiungi commento","Add wallet":"Aggiungi un portafoglio","Address":"Indirizzo","Address Type":"Tipo di indirizzo","Advanced":"Avanzato","Alias":"Alias","Alias for {{index.walletName}}":"Alias per {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Tutti i contributori alla traduzione di Copay sono i benvenuti. Iscriviti a crowdin e unisciti al progetto Copay presso","All transaction requests are irreversible.":"Tutte le richieste di transazione sono irreversibili.","Alternative Currency":"Valuta alternativa","Amount":"Ammontare","Amount below minimum allowed":"Importo inferiore al minimo consentito","Amount in":"Importo in","Are you sure you want to delete the recovery phrase?":"Sei sicuro di voler cancellare la frase di recupero?","Are you sure you want to delete this wallet?":"Sei sicuro di voler eliminare questo portafoglio?","Auditable":"Controllabile","Available Balance":"Saldo disponibile","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Tempo medio di conferma: {{fee.nbBlocks * 10}} minuti","Back":"Indietro","Backup":"Backup","Backup failed":"Backup non riuscito","Backup Needed":"Backup necessario","Backup now":"Esegui backup ora","Bad wallet invitation":"Invito al wallet non corretto","Balance By Address":"Bilancio per indirizzo","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Prima di ricevere del denaro, devi fare un un backup del tuo portafoglio. Se si perde questo dispositivo, sarà impossibile accedere ai tuoi fondi senza un backup.","BETA: Android Key Derivation Test:":"BETA: Test di derivazione di chiave Android:","BIP32 path for address derivation":"Percorso BIP32 per generare l'indirizzo","Bitcoin address":"Indirizzo Bitcoin","Bitcoin Network Fee Policy":"Criterio delle Commissioni del Bitcoin Network","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Le transazioni bitcoin possono includere una tassa raccolta dai minatori della rete. Più alta è la commissione, maggiore sarà l'incentivo per un minatore a includere tale transazione in un blocco. Le commissioni attuali sono in base al carico della rete e ai criteri selezionati.","Bitcoin URI is NOT valid!":"Il Bitcoin URI NON è valido!","Broadcast Payment":"Diffusione del Pagamento","Broadcasting transaction":"Diffondendo la transazione","Browser unsupported":"Browser non supportato","Calculating fee":"Calcolo commissione","Cancel":"Annulla","Cancel and delete the wallet":"Cancella e rimuovi il portafoglio","Cannot create transaction. Insufficient funds":"Impossibile creare la transazione. Fondi non sufficienti","Cannot join the same wallet more that once":"Non è possibile aggiungere un portafoglio più di una volta","Cannot sign: The payment request has expired":"Impossibile firmare: la richiesta di pagamento è scaduta","Certified by":"Certificato da","Changing wallet alias only affects the local wallet name.":"Il cambiamento degli alias dei portafogli influenza solo il nome del portafoglio locale.","Chinese":"Cinese","Choose a backup file from your computer":"Seleziona un file di backup dal tuo computer","Clear cache":"Svuota la cache","Close":"Chiudi","Color":"Colore","Comment":"Commento","Commit hash":"Commit hash","Confirm":"Conferma","Confirm your wallet recovery phrase":"Confermare la vostra frase di recupero del portafoglio","Confirmations":"Conferme","Congratulations!":"Complimenti!","Connecting to Coinbase...":"Connessione a Coinbase...","Connecting to Glidera...":"Connessione a Glidera...","Connection reset by peer":"Connessione ripristinata dall'utente","Continue":"Continua","Copayer already in this wallet":"Copayer già in questo portafoglio","Copayer already voted on this spend proposal":"Copayer già votato su questa proposta","Copayer data mismatch":"Mancata corrispondenza dei dati del copayer","Copayers":"Copayers","Copied to clipboard":"Copiato negli appunti","Copy this text as it is to a safe place (notepad or email)":"Copia questo testo cosí com'è in un posto sicuro (blocco note o email)","Copy to clipboard":"Copia negli appunti","Could not access the wallet at the server. Please check:":"Non può accedere al portafoglio sul server. Si prega di controllare:","Could not access wallet":"Impossibile accedere al portafoglio","Could not access Wallet Service: Not found":"Impossibile accedere al Wallet Service: non trovato","Could not broadcast payment":"Impossibile trasmettere il pagamento","Could not build transaction":"Non è possibile generare la transazione","Could not create address":"Impossibile creare un indirizzo","Could not create payment proposal":"Non posso creare la proposta di pagamento","Could not create using the specified extended private key":"Non posso crearlo utilizzando la chiave privata estesa specificata","Could not create using the specified extended public key":"Non è possibile creare usando questa chiave estesa pubblica","Could not create: Invalid wallet recovery phrase":"Impossibile creare: Frase di recupero portafoglio non valida","Could not decrypt file, check your password":"Impossibile decifrare il file, controlla la tua password","Could not delete payment proposal":"Impossibile eliminare la proposta di pagamento","Could not fetch payment information":"Impossibile recuperare le informazioni di pagamento","Could not get fee value":"Non ha ottenuto il valore della commissione","Could not import":"Impossibile importare","Could not import. Check input file and spending password":"Impossibile importare. Controlla il file da importare e la password di spesa","Could not join wallet":"Impossibile partecipare al portafoglio","Could not recognize a valid Bitcoin QR Code":"Impossibile riconoscere un Codice QR Bitcoin valido","Could not reject payment":"Impossibile rifiutare il pagamento","Could not send payment":"Impossibile inviare il pagamento","Could not update Wallet":"Impossibile aggiornare il Portafoglio","Create":"Crea","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Crea portafoglio {{requiredCopayers}}-di-{{totalCopayers}}","Create new wallet":"Crea nuovo portafoglio","Create, join or import":"Crea, partecipa o importa","Created by":"Creato da","Creating transaction":"Creazione transazione","Creating Wallet...":"Creazione Portafoglio...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Tassa corrente per questa policy: {{fee.feePerKBUnit}}/kiB","Czech":"Ceco","Date":"Data","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Decodificare un portafoglio potrebbe impiegare circa 5 minuti su questo dispositivo. Attendere e tenere l'applicazione aperta.","Delete it and create a new one":"Eliminalo e creane uno nuovo","Delete Payment Proposal":"Elimina Proposta di Pagamento","Delete recovery phrase":"Elimina frase di recupero","Delete Recovery Phrase":"Elimina Frase di Recupero","Delete wallet":"Elimina portafoglio","Delete Wallet":"Elimina Portafoglio","Deleting Wallet...":"Eliminazione del portafoglio...","Derivation Path":"Percorso derivato","Derivation Strategy":"Strategia di derivazione","Description":"Descrizione","Details":"Dettagli","Disabled":"Disabilitato","Do not include private key":"Non includere la chiave privata","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Non vedi la tua lingua su Crowdin? Contatta il proprietario su Crowdin! Ci piacerebbe supportare la lingua.","Done":"Fatto","Download":"Download","Economy":"Economia","Edit":"Modifica","Edit comment":"Modifica commento","Edited by":"Modificato da","Email for wallet notifications":"Email per le notifiche del portafoglio","Email Notifications":"Notifiche Email","Empty addresses limit reached. New addresses cannot be generated.":"Raggiunto il limite degli indirizzi vuoti. Non possono essere generati nuovi indirizzi.","Enable Coinbase Service":"Abilitare servizio Coinbase","Enable Glidera Service":"Abilitare servizio Glidera","Enable push notifications":"Abilitare le notifiche push","Encrypted export file saved":"Backup criptato salvato","Enter the recovery phrase (BIP39)":"Inserire la frase di recupero (BIP39)","Enter your password":"Inserisci la tua password","Enter your spending password":"Inserisci la tua password di spesa","Error at Wallet Service":"Errore del Wallet Service","Error creating wallet":"Errore creazione portafoglio","Expired":"Scaduta","Expires":"Scadenza","Export options":"Opzioni di esportazione","Export to file":"Esporta in un file","Export Wallet":"Esporta portafoglio","Exporting via QR not supported for this wallet":"Per questo portafoglio non è supportata l'esportazione tramite QR","Extended Public Keys":"Chiave pubblica estesa","Extracting Wallet Information...":"Estrazione delle informazioni sul portafoglio...","Failed to export":"Esportazione non riuscita","Failed to verify backup. Please check your information":"Impossibile verificare il backup. Si prega di controllare le informazioni","Family vacation funds":"Fondi vacanza di famiglia","Fee":"Tassa","Fetching Payment Information":"Recuperando le informazioni del pagamento","File/Text":"File/Testo","Finger Scan Failed":"Scansione dito fallita","Finish":"Fine","For audit purposes":"Per finalità di controllo","French":"Francese","From the destination device, go to Add wallet > Import wallet and scan this QR code":"Dal dispositivo di destinazione, andare in Aggiungi portafoglio > Importare portafoglio e scansionare questo codice QR","Funds are locked by pending spend proposals":"I fondi sono bloccati in attesa della proposta di pagamento","Funds found":"Fondi trovati","Funds received":"Fondi ricevuti","Funds will be transferred to":"I fondi saranno trasferiti a","Generate new address":"Genera un nuovo indirizzo","Generate QR Code":"Genera un codice QR","Generating .csv file...":"Genera un file .csv...","German":"Tedesco","Getting address for wallet {{selectedWalletName}} ...":"Ottengo l'indirizzo per il portafoglio {{selectedWalletName}}...","Global preferences":"Preferenze globali","Hardware wallet":"Portafoglio hardware","Hardware Wallet":"Portafoglio Hardware","Hide advanced options":"Nascondi opzioni avanzate","I affirm that I have read, understood, and agree with these terms.":"Affermo di aver letto, compreso e accettato questi termini.","I AGREE. GET STARTED":"Sono d'accordo. INIZIARE","Import":"Importa","Import backup":"Importa backup","Import wallet":"Importa un portafoglio","Importing Wallet...":"Importazione del Portafoglio...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"In nessun caso gli autori del software, dipendenti e affiliati di Bitpay, detentori del copyright o BitPay, Inc potranno essere ritenuti responsabili per qualsiasi danno o altra responsabilità, sia in un'azione di contratto, torto, o altro, derivanti da, su o in relazione al software.","In order to verify your wallet backup, please type your password:":"Per verificare il backup del tuo portafoglio, inserire la password:","Incorrect address network":"Indirizzo della rete incorretto","Incorrect code format":"Formato qrcode non corretto","Insufficient funds":"Fondi insufficienti","Insufficient funds for fee":"Fondi insufficienti per la commissione","Invalid":"Invalido","Invalid account number":"Numero di conto non valido","Invalid address":"Indirizzo non valido","Invalid derivation path":"Percorso di derivazione non valido","Invitation to share a Copay Wallet":"Invito a condividere un portafoglio Copay","Italian":"Italiano","Japanese":"Giapponese","John":"John","Join":"Unisciti","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Unisciti al mio portafoglio Copay. Ecco il codice di invito: {{secret}} Puoi scaricare Copay dal tuo telefono o computer da https://copay.io","Join shared wallet":"Unisciti al portafoglio condiviso","Joining Wallet...":"Unendo al portafoglio...","Key already associated with an existing wallet":"Chiave già associata ad un portafoglio esistente","Label":"Etichetta","Language":"Lingua","Last Wallet Addresses":"Indirizzi dell'ultimo portafoglio","Learn more about Copay backups":"Ulteriori informazioni sui backup Copay","Loading...":"Caricamento...","locked by pending payments":"bloccati da pagamenti in sospeso","Locktime in effect. Please wait to create a new spend proposal":"Locktime in effetto. Si prega di attendere per creare una nuova proposta di pagamento","Locktime in effect. Please wait to remove this spend proposal":"Locktime in effetto. Si prega di attendere per rimuovere questa proposta di pagamento","Make a payment to":"Effettuare un pagamento a","Matches:":"Corrispondenze:","me":"io","Me":"Io","Memo":"Nota","Merchant message":"Messaggio commerciale","Message":"Messaggio","Missing parameter":"Parametro mancante","Missing private keys to sign":"Chiavi private per la firma mancanti","Moved":"Spostato","Multiple recipients":"Più destinatari","My Bitcoin address":"Il mio indirizzo Bitcoin","My contacts":"I miei contatti","My wallets":"I miei portafogli","Need to do backup":"Necessario eseguire backup","Network":"Network","Network connection error":"Errore di connessione alla rete","New Payment Proposal":"Nuova proposta di pagamento","New Random Recovery Phrase":"Nuova Frase Casuale di Recupero","No hardware wallets supported on this device":"Nessun portafoglio hardware supportato da questo dispositivo","No transactions yet":"Ancora nessuna transazione","Normal":"Normale","Not authorized":"Non autorizzato","Not completed":"Non completato","Not enough funds for fee":"Non ci sono abbastanza fondi per la commissione","Not valid":"Non valido","Note":"Nota","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Nota: un totale di {{amountAboveMaxSizeStr}} sono stati esclusi. È stata superata la dimensione massima consentita per una transazione","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Nota: un totale di {{amountBelowFeeStr}} sono stati esclusi. Questi fondi provengono da UTXO inferiori rispetto alla tariffa di rete richiesta.","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"Nota: Per importare un portafoglio da un software di terze parti, si prega di andare in Aggiungi portafoglio > Crea portafoglio, e specificare la frase di recupero.","Official English Disclaimer":"Dichiarazione di esclusione di responsabilità ufficiale in inglese","OKAY":"VA BENE","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"Una volta che avrai copiato la tua frase di recupero portafoglio su un foglio di carta, si consiglia di cancellarla da questo dispositivo.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Sono mostrati solo gli indirizzi principali (non modificati). Gli indirizzi in questo elenco non sono stati verificati localmente in questo momento.","Open Settings app":"Aprire Impostazioni app","optional":"opzionale","Paper Wallet Private Key":"Chiave privata del Paper Wallet","Participants":"Partecipanti","Passphrase":"Passphrase","Password":"Password","Password required. Make sure to enter your password in advanced options":"Password necessaria. Assicurarsi di immettere la password nelle impostazioni avanzate","Paste invitation here":"Incolla qui l'invito","Paste the backup plain text code":"Incolla qui il codice di backup","Paste your paper wallet private key here":"Incolla la chiave privata del tuo Paper Wallet qui","Pasted from clipboard":"Incollato dagli appunti","Pay To":"Paga A","Payment Accepted":"Pagamento Accettato","Payment accepted, but not yet broadcasted":"Pagamento accettato, ma non ancora inviata alla rete","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Pagamento accettato. Esso sarà trasmesso attraverso la rete Glidera. Nel caso in cui ci fosse un problema, si potrà eliminarlo 6 ore dopo che è stato creato.","Payment details":"Dettagli pagamento","Payment expires":"Pagamento scaduto","Payment Proposal":"Proposta di Pagamento","Payment Proposal Created":"Proposta di Pagamento Creata","Payment Proposal Rejected":"Proposta di Pagamento Rifiutata","Payment Proposal Rejected by Copayer":"Proposta di Pagamento Rifiutata dai Copayers","Payment Proposal Signed by Copayer":"Proposta di Pagamento Firmata dai Copayers","Payment Proposals":"Proposte di Pagamento","Payment Protocol Invalid":"Protocollo di pagamento non valido","Payment Protocol not supported on Chrome App":"Proposta di Pagamento non supportata dall'applicazione Chrome","Payment Rejected":"Pagamento Rifiutato","Payment request":"Richiesta di pagamento","Payment Sent":"Pagamento Inviato","Payment to":"Pagamento a","Pending Confirmation":"In attesa di conferma","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Elimina definitivamente questo portafoglio. QUESTA AZIONE NON PUO' ESSERE INVERTITA","Personal Wallet":"Portafoglio Personale","Please enter the recovery phrase":"Si prega di inserire la frase di recupero","Please enter the required fields":"Per favore completa i campi richiesti","Please enter the wallet recovery phrase":"Si prega di inserire la frase di recupero del portafoglio","Please tap the words in order to confirm your backup phrase is correctly written.":"Si prega di toccare le parole al fine di confermare la che vostra frase di backup è scritta correttamente.","Please upgrade Copay to perform this action":"Si prega di aggiornare Copay per eseguire questa azione","Please wait to be redirected...":"Si prega di attendere per il reindirizzamento...","Please, select your backup file":"Per favore, selezione il tuo file di backup","Polish":"Polacco","Preferences":"Preferenze","Preparing backup...":"Preparando il backup...","preparing...":"preparazione...","Press again to exit":"Premi ancora per uscire","Priority":"Priorità","Private key is encrypted, cannot sign":"La chiave privata è crittografata, non è possibile accedere","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Le notifiche push per Copay sono attualmente disabilitate. Abilitarle nel menu Impostazioni.","QR Code":"Codice QR","QR-Scanner":"QR-Scanner","Receive":"Ricevi","Received":"Ricevuti","Recipients":"Destinatari","Recovery Phrase":"Frase di Recupero","Recovery phrase deleted":"Frase di recupero eliminata","Recreate":"Ricrea","Recreating Wallet...":"Ricreando Portafoglio...","Reject":"Rifiuta","Release Information":"Informazioni Release","Remove":"Rimuovere","Repeat password":"Ripeti password","Repeat the password":"Ripeti la password","Repeat the spending password":"Ripetere la password di spesa","Request a specific amount":"Richiedi un importo specifico","Request Spending Password":"Richiedere Password di spesa","Required":"Richiesto","Required number of signatures":"Selezionare il numero necessario di firme","Retrieving inputs information":"Recupero delle informazioni iniziali","Russian":"Russo","Save":"Salva","Scan addresses for funds":"Scansione degli indirizzi per fondi","Scan Fingerprint":"Scansione impronte","Scan Finished":"Scansione terminata","Scan status finished with error":"La scansione è terminata con un errore","Scan Wallet Funds":"Scansione dei fondi del portafoglio","Scan your fingerprint please":"Per cortesia procedere alla scansione dell'impronta digitale","Scanning Wallet funds...":"Scansione fondi Portafoglio...","Search transactions":"Ricerca transazioni","Search Transactions":"Cerca Transazioni","Security preferences":"Preferenze di sicurezza","See it on the blockchain":"Guardala nella blockchain","Select a backup file":"Seleziona un file di backup","Select a wallet":"Selezionare un portafoglio","Self-signed Certificate":"Certificato autofirmato","Send":"Invia","Send addresses by email":"Invia indirizzi via Email","Send bitcoin":"Invia bitcoin","Send by email":"Invia via email","Send Max":"Invia il massimo","Sending":"Invio in corso","Sending transaction":"Invio transazione","Sent":"Inviato","Server response could not be verified":"La risposta del server non può essere verificata","Session log":"Registro sessione","SET":"IMPOSTA","Set default url":"Imposta url predefinito","Set up a password":"Imposta una password","Set up a spending password":"Impostare una password di spesa","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Impostando le notifiche e-mail potrebbe indebolire la tua privacy se il provider di servizio del portafoglio è compromesso. Le informazioni disponibili ad un utente malintenzionato potrebbero includere l'indirizzo del tuo portafoglio e il suo saldo, ma non di più.","Settings":"Impostazioni","Share address":"Condividi l'indirizzo","Share invitation":"Condividi l'invito","Share this invitation with your copayers":"Condividi questo invito con i tuoi copayers","Share this wallet address to receive payments":"Condividere questo indirizzo di portafoglio per ricevere pagamenti","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Condividi questo indirizzo del portafoglio per ricevere pagamenti. Per proteggere la tua privacy, ad ogni utilizzo sono generati nuovi indirizzi.","Shared Wallet":"Portafoglio Condiviso","Show advanced options":"Mostra opzioni avanzate","Signatures rejected by server":"Firme rifiutate dal server","Signing transaction":"Firmando transazione","Single Address Wallet":"Singolo indirizzo di portafoglio","Spanish":"Spagnolo","Specify Recovery Phrase...":"Specificare la frase di recupero...","Spend proposal is not accepted":"La proposta di pagamento non è accettata","Spend proposal not found":"Proposta di pagamento non trovata","Spending Password needed":"Necessaria password di spesa","Spending Passwords do not match":"Le password di spesa non combaciano","Success":"Completato","Super Economy":"Super Economica","Sweep paper wallet":"Spazzare il portafoglio di carta","Sweep Wallet":"Portafoglio Sweep","Sweeping Wallet...":"Spazzolamento Portafoglio...","Tap and hold to show":"Toccare e tenere premuto per mostrare","Tap to retry":"Tocca per riprovare","Terms of Use":"Termini di Utilizzo","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Gli autori del software, dipendenti e affiliati di Bitpay, detentori del copyright e BitPay, Inc non possono recuperare la tua password o chiave privata se si perde o si dimentica e non può garantire la conferma della transazione poiché non hanno controllo della rete Bitcoin.","The derivation path":"Il percorso di derivazione","The Ledger Chrome application is not installed":"Non è installata l'applicazione di contabilità Chrome","The password of the recovery phrase (if set)":"La password della frase recupero (se impostata)","The payment was created but could not be completed. Please try again from home screen":"Il pagamento è stato creato ma è stato impossibile completarlo. Per favore prova di nuovo dalla schermata iniziale","The payment was removed by creator":"Il pagamento è stato rimosso dal creatore","The recovery phrase could require a password to be imported":"La frase di recupero potrebbe richiedere una password per essere importata","The request could not be understood by the server":"La richiesta potrebbe non essere compresa dal server","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Il software non costituisce un account dove BitPay o altre terze parti servono come intermediari finanziari o custodi dei tuoi bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Il software che si sta per utilizzare è un portafoglio libero, open source e con multi-firma digitale.","The spend proposal is not pending":"La proposta di pagamento non è in sospeso","The wallet \"{{walletName}}\" was deleted":"Il portafoglio {{walletName}} è stato eliminato","The Wallet Recovery Phrase could require a password to be imported":"La frase di recupero portafoglio potrebbe richiedere una password per essere importata","The wallet service URL":"L'URL del servizio di portafoglio","There are no wallets to make this payment":"Non ci sono portafogli per effettuare questo pagamento","There is a new version of Copay. Please update":"C'è una nuova versione di Copay. Si prega di aggiornare","There is an error in the form":"C'è un errore nel form","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"Questa frase di recupero è stata creata con una password. Per recuperare questo portafoglio sono necessari sia la frase di recupero e che la password.","This transaction has become invalid; possibly due to a double spend attempt.":"Questa transazione è diventata invalida; forse a causa di un tentativo di doppia spesa.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Questo portafoglio non è registrato al Bitcore Wallet Service (BWS). Puoi ricrearlo dalle informazioni locali.","Time":"Tempo","To":"A","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Per ripristinare questo portafoglio condiviso di {{index.m}}-{{index.n}} tu avrai bisogno","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"La misura massima consentita dalla legge, questo software è fornito \"così com'è\" e alcuna dichiarazione o garanzia può essere fatto di alcun tipo, esplicite o implicite, comprese ma non limitate alle garanzie di commerciabilità, adattamenti o uno scopo particolare e non violazione.","too long!":"troppo lungo!","Total Locked Balance":"Totale Importo Bloccato","Total number of copayers":"Numero totale di copayer","Touch ID Failed":"Touch ID Fallito","Transaction":"Transazione","Transaction already broadcasted":"Transazione già trasmessa","Transaction History":"Cronologia delle transazioni","Translation Credits":"Ringraziamenti per la traduzione","Translators":"Traduttori","Try again":"Riprova","Type the Recovery Phrase (usually 12 words)":"Digitare la Frase di Recupero (tipicamente 12 parole)","Unconfirmed":"Non confermato","Unit":"Unità","Unsent transactions":"Transazioni non inviate","Updating transaction history. Please stand by.":"Aggiornamento cronologia delle transazioni. Siete pregati di attendere.","Updating Wallet...":"Aggiornamento portafoglio...","Use Unconfirmed Funds":"Usa i fondi non confermati","Validating recovery phrase...":"Validazione della frase di recupero...","Validating wallet integrity...":"Validazione integrità del portafoglio...","Version":"Versione","View":"Visualizza","Waiting for copayers":"In attesa di copayers","Waiting for Ledger...":"In attesa del Ledger...","Waiting for Trezor...":"In attesa del Trezor...","Waiting...":"In attesa...","Wallet already exists":"Il portafoglio esiste già","Wallet already in Copay":"Portafoglio già in Copay","Wallet Configuration (m-n)":"Configurazione di portafoglio (m-n)","Wallet Export":"Esportazione portafoglio","Wallet Id":"Id portafoglio","Wallet incomplete and broken":"Portafoglio incompleto e danneggiato","Wallet Information":"Informazioni sul portafoglio","Wallet Invitation":"Invito Portafoglio","Wallet Invitation is not valid!":"Invito Portafoglio non valido!","Wallet is full":"Portafoglio è pieno","Wallet is locked":"Il portafoglio è bloccato","Wallet is not complete":"Portafoglio non è completo","Wallet name":"Nome Portafoglio","Wallet Name (at creation)":"Nome portafoglio (al momento della creazione)","Wallet needs backup":"Il portafoglio richiede password","Wallet Network":"Portafoglio di rete","Wallet not found":"Portafoglio non trovato","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"Portafoglio non registrato presso il servizio di portafoglio. Ricrearlo da \"Creare portafoglio\" tramite \"Opzioni avanzate\" per impostare la tua frase di recupero","Wallet Preferences":"Preferenze del Portafogli","Wallet Recovery Phrase":"Frase di recupero del portafoglio","Wallet Recovery Phrase is invalid":"Frase di recupero del portafoglio non è valida","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"Frase di recupero del portafoglio non disponibile. È comunque possibile esportarla da Avanzate > Esporta.","Wallet service not found":"Wallet service non trovato","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"ATTENZIONE: La derivazione della chiave non funziona su questo dispositivo/portafoglio. Le operazioni non possono essere eseguite su questo portafoglio.","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"AVVISO: L'esclusione della chiave privata permette di controllare il bilancio del portafoglio, la cronologia delle transazioni e creare proposte di spesa dall'esportazione. Tuttavia, non consente di approvare le proposte (firma), così fondi non saranno accessibili dall'esportazione.","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"ATTENZIONE: La password non può essere recuperata. Assicurati di scrivertela. Il portafoglio non può essere ripristinato senza la password.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"AVVISO: La chiave privata di questo portafoglio non è disponibile. L'esportazione permette di controllare il bilancio del portafoglio, la cronologia delle transazioni e creare proposte di spesa dall'esportazione. Tuttavia, non consente di approvare le proposte (firma), così fondi non saranno accessibili dall'esportazione.","Warning: this transaction has unconfirmed inputs":"Attenzione: questa transazione ha inputs non confermati","WARNING: UNTRUSTED CERTIFICATE":"ATTENZIONE: CERTIFICATO NON ATTENDIBILE","WARNING: Wallet not registered":"AVVISO: Portafoglio non registrato","Warning!":"Attenzione!","We reserve the right to modify this disclaimer from time to time.":"Ci riserviamo il diritto di modificare di volta in volta il presente disclaimer.","WELCOME TO COPAY":"BENVENUTO A COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Mentre il software è stato sottoposto a test beta e continua a essere migliorato da un feedback dall'utente open source e comunità di sviluppatori, non possiamo garantire che non ci sarà nessun bug nel software.","Write your wallet recovery phrase":"Scrivi la tua frase di recupero del portafoglio","Wrong number of recovery words:":"Numero errato delle parole di recupero:","Wrong spending password":"Password per spesa errata","Yes":"Sì","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"L'utente riconosce che l'utilizzo di questo software è a tua discrezione e nel rispetto di tutte le leggi applicabili.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Tu sei responsabile per la custodia le password, le coppie di chiavi private, PINs e qualsiasi altro codice da utilizzare per accedere al software.","You assume any and all risks associated with the use of the software.":"Vi assumete tutti i rischi associati all'utilizzo del software.","You backed up your wallet. You can now restore this wallet at any time.":"È stato eseguito il Backup del tuo portafoglio. È ora possibile ripristinare questo portafoglio in qualsiasi momento.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"* Puoi installare in modo sicuro il tuo portafoglio su un altro device e usarlo da più dispositivi contemporaneamente.","You do not have any wallet":"Non hai alcun portafoglio","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"Devi avere la frase di recupero portafoglio per ripristinare questo portafoglio personale. Scrivitela e tienila in un posto sicuro.","Your nickname":"Il tuo nickname","Your password":"La tua password","Your spending password":"La tua password di spesa","Your wallet has been imported correctly":"Il tuo portafoglio è stato importato correttamente","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"La chiave del tuo portafoglio verrà crittografata. La Password di Spesa non può essere recuperata. Assicurati quindi di scriverla su di un foglio di carta","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"La tua frase di recupero portafoglio e accesso al server che ha coordinato la creazione iniziale del portafoglio. Hai ancora bisogno delle chiavi {{index.m}} prima di spendere."}); - gettextCatalog.setStrings('ja', {"(possible double spend)":"(二重払い可能性あり)","(Trusted)":"(信頼済み)","[Balance Hidden]":"[残高非表示中]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} のビットコインネットワーク手数料が差し引かれます。","{{feeRateStr}} of the transaction":"{{feeRateStr}} のレート","{{index.m}}-of-{{index.n}}":"{{index.m}}-of-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"あと {{index.result.length - index.txHistorySearchResults.length}}","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} 個の取引ダウンロード済み","{{item.m}}-of-{{item.n}}":"{{item.m}}-of-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* 送金の提案の取下げは①他のウォレット参加者に署名されていなかった場合、提案者に提案を取り下げることができます。②提案の起案から24時間が経っても解決しなかった場合、全員に取り下げることができます。","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"Copayウォレットとその中にある秘密鍵の情報を紛失してしまい、尚且つバックアップが無い、若しくはそのバックアップを暗号化した際のパスワードが分からないなどの状況に陥ってしまえば、そのウォレットに含まれた全てのビットコインが永久送金不可能となってしまうことを認識し、同意するものとします。","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"または 従来ウォレットエクスポートファイル1つに加えて残りの必須人数の復元フレーズ (例: 3-of-5 ウォレットでは従来ウォレットバックアップ1つに加え、他の参加者2人分の復元フレーズさえあればウォレットは復元できます)","OR the wallet recovery phrase of all copayers in the wallet":"または 参加者 全員 のウォレット復元フレーズ","OR the wallet recovery phrases of all copayers in the wallet":"または 参加者 全員 のウォレット復元フレーズ","A multisignature bitcoin wallet":"マルチシグネチャビットコインウォレット","About Copay":"Copayについて","Accept":"承諾","Account":"ポケット","Account Number":"ポケット番号","Activity":"履歴","Add a new entry":"新規追加","Add a Password":"パスワードを追加","Add an optional password to secure the recovery phrase":"フレーズを守るために任意のパスワードをかけて下さい","Add comment":"コメントを追加","Add wallet":"ウォレットを追加","Address":"アドレス","Address Type":"アドレスの種類","Advanced":"上級者向け","Alias":"通称","Alias for {{index.walletName}}":"{{index.walletName}} の通称設定","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Copayの翻訳は簡単に投稿することができます。crowdin.comのアカウント作成の後、自由にご参加いただけるプロジェクトページはこちら","All transaction requests are irreversible.":"署名が完了してしまった取引は取り消しが不可能となります。","Alternative Currency":"表示通貨","Amount":"金額","Amount below minimum allowed":"送金可能最少額を下回っています","Amount in":"換算済金額","Are you sure you want to delete the recovery phrase?":"復元フレーズを削除してもよろしいですか?","Are you sure you want to delete this wallet?":"本当にこのウォレットを削除しても\n宜しいですか?","Auditable":"監査用","Available Balance":"送金可能残高","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"承認までの時間(平均): {{fee.nbBlocks * 10}} 分","Back":"戻る","Backup":"バックアップ","Backup failed":"バックアップ失敗","Backup Needed":"要バックアップ","Backup now":"今すぐバックアップ","Bad wallet invitation":"不正なウォレット招待コード","Balance By Address":"アドレスごとの残高","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"お金を受け取る前に、このウォレットのバックアップを取っておくことを必ずしていただきます。一ウォレットごとにバックアップは一回です。バックアップを取らないまま、この端末が紛失・故障されてしまったら全残高が消失されてしまいます。","BETA: Android Key Derivation Test:":"β機能: アンドロイド鍵派生テスト","BIP32 path for address derivation":"階級アドレス派生のパス","Bitcoin address":"ビットコインアドレス","Bitcoin Network Fee Policy":"ビットコインネットワークの手数料設定","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"円滑な送金をしていただくために、ビットコインの送金には少量の手数料を付けることが義務付けられております。この手数料はビットコインのネットワークを運用する人たちに寄付され、より高い手数料であればより優先的にブロックに含まれ、承認されます。選択された手数料基準やネットワークの混雑状況により、その時点で払われるべき手数料が変動することがあります。","Bitcoin URI is NOT valid!":"Bitcoin URI が無効です!","Broadcast Payment":"取引送信","Broadcasting transaction":"取引送信中","Browser unsupported":"ブラウザ未対応","Buy and Sell":"購入と売却","Calculating fee":"手数料計算中...","Cancel":"キャンセル","Cancel and delete the wallet":"キャンセルし、ウォレットを削除","Cannot create transaction. Insufficient funds":"取引を作成できません。資金不足です。","Cannot join the same wallet more that once":"同じ端末で同じウォレットに複数回参加することができません。","Cannot sign: The payment request has expired":"署名できません: 支払い請求の期限が切れています。","Certified by":"証明元:","Changing wallet alias only affects the local wallet name.":"ウォレット通称を変更しても、この端末でしか変わりません。","Chinese":"中国語","Choose a backup file from your computer":"パソコンからバックアップファイルを選択して下さい。","Clear cache":"キャッシュを消去","Close":"閉じる","Color":"色","Comment":"コメント","Commit hash":"コミットのハッシュ値","Confirm":"確認","Confirm your wallet recovery phrase":"復元フレーズを確認","Confirmations":"承認回数","Congratulations!":"おめでとうございます!","Connecting to Coinbase...":"Coinbase に接続中…","Connecting to Glidera...":"Glidera に接続中…","Connection reset by peer":"接続がピアによってリセットされました","Continue":"続ける","Copayer already in this wallet":"ウォレット参加者が既に存在しています。","Copayer already voted on this spend proposal":"ウォレット参加者が既に送金の提案の意思表明をしています。","Copayer data mismatch":"ウォレット参加者のデータ不整合","Copayers":"ウォレット参加者","Copied to clipboard":"クリップボードにコピーしました","Copy this text as it is to a safe place (notepad or email)":"このテキストを安全な場所に貼り付けて保管して下さい (メモ帳やメールの下書きなど)","Copy to clipboard":"クリップボードへコピー","Could not access the wallet at the server. Please check:":"サーバーにてウォレットの確認ができませんでした。こちらをご確認下さい:","Could not access wallet":"ウォレットにアクセスできませんでした。","Could not access Wallet Service: Not found":"Wallet Serviceにアクセスできませんでした: 見つかりません","Could not broadcast payment":"送金を配信できませんでした。","Could not build transaction":"取引を作成できませんでした。","Could not create address":"アドレスを生成できませんでした。","Could not create payment proposal":"送金の提案を作成できませんでした","Could not create using the specified extended private key":"指定された拡張秘密鍵で作成できませんでした。","Could not create using the specified extended public key":"指定された拡張公開鍵で作成できませんでした。","Could not create: Invalid wallet recovery phrase":"作成できません:ウォレットの復元フレーズが不正です。","Could not decrypt file, check your password":"複合化できませんでした。パスワードが正しいかご確認下さい。","Could not delete payment proposal":"送金の提案を削除できませんでした","Could not fetch payment information":"支払い情報が取得できませんでした。","Could not get fee value":"手数料の金額を取得できませんでした。","Could not import":"インポートできませんでした。","Could not import. Check input file and spending password":"インポートできませんでした。入力ファイルとパスワードが正しいかご確認下さい。","Could not join wallet":"ウォレットに参加できませんでした。","Could not recognize a valid Bitcoin QR Code":"有効なビットコインQRコードが認識できませんでした。","Could not reject payment":"送金を却下できませんでした。","Could not send payment":"送金できませんでした。","Could not update Wallet":"ウォレットが更新できませんでした。","Create":"作成","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"{{requiredCopayers}}-of-{{totalCopayers}} ウォレットを作成","Create new wallet":"新規ウォレット作成","Create, join or import":"作成、参加、インポート","Created by":"作成者","Creating transaction":"取引作成中…","Creating Wallet...":"ウォレット作成中…","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"この手数料基準の現レート: {{fee.feePerKBUnit}}/kiB","Czech":"チェコ語","Date":"日付","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"暗号化されたペーパーウォレットはこの端末だと解読に5分以上掛かる場合がございます。アプリを閉じたり他のアプリに切り替えたりせずに、終了するまでそのままお待ち下さい。","Delete it and create a new one":"削除して新規作成","Delete Payment Proposal":"送金の提案を削除","Delete recovery phrase":"復元フレーズを削除","Delete Recovery Phrase":"復元フレーズを削除","Delete wallet":"ウォレットを削除","Delete Wallet":"ウォレットを削除","Deleting Wallet...":"ウォレット削除中…","Derivation Path":"派生パス","Derivation Strategy":"派生パス","Description":"詳細","Details":"詳細","Disabled":"無効","Do not include private key":"秘密鍵を含めない","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"ご自分の言語はCrowdinで見当たりませんか?Crowdinの管理者に連絡とってみてください。是非とも対応したく思っております。","Done":"完了","Download":"ダウンロード","Economy":"節約","Edit":"編集","Edit comment":"コメントを編集","Edited by":"編集者","Email for wallet notifications":"メールによるウォレットのお知らせ","Email Notifications":"メールのお知らせ","Empty addresses limit reached. New addresses cannot be generated.":"未使用アドレスを生成しすぎたため、これ以上アドレスを生成することができません。","Enable Coinbase Service":"Coinbase連携を有効にする","Enable Glidera Service":"Glidera連携を有効にする","Enable push notifications":"プッシュ通知を有効化","Encrypted export file saved":"暗号化されたバックアップ保存しました","Enter the recovery phrase (BIP39)":"復元フレーズの単語をご入力下さい。","Enter your password":"パスワードを入力して下さい。","Enter your spending password":"パスワードを入力してください","Error at Wallet Service":"Wallet Serviceにてエラー","Error creating wallet":"ウォレット作成時にエラー","Expired":"期限切れ","Expires":"有効期限:","Export options":"エクスポート設定","Export to file":"ファイルへのエクスポート","Export Wallet":"ウォレットをエクスポート","Exporting via QR not supported for this wallet":"このウォレットはQRによるエクスポートに対応していません","Extended Public Keys":"拡張公開鍵","Extracting Wallet Information...":"ウォレット情報を抽出中…","Failed to export":"エクスポートに失敗しました。","Failed to verify backup. Please check your information":"バックアップを確認できませんでした。転記した情報をご確認ください。","Family vacation funds":"家族旅行貯金","Fee":"手数料","Fetching Payment Information":"支払い情報要求しています…","File/Text":"ファイル/テキスト","Finger Scan Failed":"指紋認証に失敗しました","Finish":"完了","For audit purposes":"監査用機能","French":"フランス語","From the destination device, go to Add wallet > Import wallet and scan this QR code":"移行先の端末では、ウォレットを追加から、ウォレットをインポートの画面でQRをスキャンして下さい。","Funds are locked by pending spend proposals":"協議中の送金の提案により、資金がロックされています。","Funds found":"残高がありました","Funds received":"着金あり","Funds will be transferred to":"送金先","Generate new address":"新規アドレスを生成","Generate QR Code":"QRコードを生成","Generating .csv file...":"CSVファイル作成中…","German":"ドイツ語","Getting address for wallet {{selectedWalletName}} ...":"「{{selectedWalletName}}」のアドレスを取得中…","Global preferences":"アプリ設定","Hardware wallet":"ハードウェアウォレット","Hardware Wallet":"ハードウェアウォレット","Hide advanced options":"詳細設定を非表示","I affirm that I have read, understood, and agree with these terms.":"内容をよく読み、理解し、同意します。","I AGREE. GET STARTED":"同意して始めます","Import":"インポート","Import backup":"バックアップをインポート","Import wallet":"ウォレットをインポート","Importing Wallet...":"ウォレットインポート中…","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"和訳は簡単な要約と考えて下さい。","In order to verify your wallet backup, please type your password:":"ウォレットのバックアップを確認するためには、復元フレーズ用のパスワードをご入力下さい。","Incorrect address network":"アドレスのネットワークが不正です。","Incorrect code format":"コードの形式が異なります","Insufficient funds":"残高不足","Insufficient funds for fee":"手数料付けるには残高が足りません","Invalid":"無効","Invalid account number":"無効なポケット番号です。","Invalid address":"不正アドレス","Invalid derivation path":"無効な派生パス","Invitation to share a Copay Wallet":"Copay共有ウォレットへの招待","Italian":"イタリア語","Japanese":"日本語","John":"山田太郎","Join":"参加","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Copayの共有ウォレット作りました: {{secret}} この招待コードを入力して、ウォレットに参加して下さい。アプリのダウンロードは https://copay.io にてどうぞ!","Join shared wallet":"共有ウォレットに参加","Joining Wallet...":"ウォレット参加中…","Key already associated with an existing wallet":"この鍵は既存のウォレットにて登録されています","Label":"ラベル","Language":"言語設定","Last Wallet Addresses":"最新ウォレットアドレス","Learn more about Copay backups":"Copay のバックアップの種類について","Loading...":"読み込み中...","locked by pending payments":"未対応送金の提案によりロック中","Locktime in effect. Please wait to create a new spend proposal":"Locktime待ち中です。新しい送金の提案が作成できるまであとしばらくお待ち下さい。","Locktime in effect. Please wait to remove this spend proposal":"Locktime待ち中です。この送金の提案が削除できるまであとしばらくお待ち下さい。","Make a payment to":"支払いは次の宛先へ","Matches:":"結果:","me":"自分","Me":"自分","Memo":"メモ","Merchant message":"お店からのメッセージ:","Message":"メッセージ","Missing parameter":"不足しているパラメータ","Missing private keys to sign":"署名するための秘密鍵がありません。","Moved":"移動済","Multiple recipients":"複数送金先","My Bitcoin address":"私のビットコインアドレス:","My contacts":"連絡先","My wallets":"アプリ内ウォレット","Need to do backup":"バックアップを行う必要があります。","Network":"ネットワーク","Network connection error":"ネットワーク接続エラー","New Payment Proposal":"新しい送金の提案","New Random Recovery Phrase":"新規復元フレーズ","No hardware wallets supported on this device":"この端末ではハードウェアウォレットがサポートされていません","No transactions yet":"取引がありません","Normal":"通常","Not authorized":"権限がありません。","Not completed":"未完了","Not enough funds for fee":"手数料含めたら残高が不足しています。","Not valid":"無効です","Note":"メモ","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"注意:合計{{amountAboveMaxSizeStr}} を除外しました。取引に許可される最大サイズを超えました","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"注意:合計 {{amountBelowFeeStr}} を除外しました。これらのビットコインは手数料よりも低い額となるため除外しました。","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"注意:他アプリのウォレットをインポートする場合、ウォレットを追加 > 新規ウォレット作成にて復元フレーズを指定するオプションを詳細設定にて有効にして下さい。","Official English Disclaimer":"公式免責事項 (英語)","OKAY":"OK","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"復元フレーズを控えたら、このデバイスから削除することをおすすめします。","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"受け取り用のアドレスしか表示していません。現時点ではローカルの端末ではアドレスの正確性を二重確認していなくて、サーバーを信じる必要があります。","Open Settings app":"設定を開く","optional":"任意","Paper Wallet Private Key":"ペーパーウォレット秘密鍵","Participants":"参加者","Passphrase":"パスワード","Password":"パスワード","Password required. Make sure to enter your password in advanced options":"パスワードが必要です。上級者向け設定にてパスワードを入力してください。","Paste invitation here":"招待コードをこちらへ貼り付けて下さい","Paste the backup plain text code":"バックアップの文字をここに貼り付けて下さい","Paste your paper wallet private key here":"ペーパーウォレットの秘密鍵をここに貼り付けて下さい","Pasted from clipboard":"クリップボードから貼り付け","Pay To":"支払い先","Payment Accepted":"支払いが完了しました","Payment accepted, but not yet broadcasted":"取引が承認されましたが、まだ送信していません。","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"取引が承認されました。Glideraより送信されます。問題があった場合、送金命令を出す6時間以内に取り消すことができます。","Payment details":"支払いの詳細","Payment expires":"支払い請求の有効期限","Payment Proposal":"送金の提案","Payment Proposal Created":"送金の提案が作成されました","Payment Proposal Rejected":"送金の提案が却下されました","Payment Proposal Rejected by Copayer":"送金の提案が他の参加者によって却下されました。","Payment Proposal Signed by Copayer":"送金の提案が他の参加者によって署名されました。","Payment Proposals":"送金の提案","Payment Protocol Invalid":"ペイメントプロトコルが不正です。","Payment Protocol not supported on Chrome App":"クロームのアプリではペイメントプロトコールがサポートされていません。","Payment Rejected":"送金が却下されました","Payment request":"支払い請求","Payment Sent":"送金が完了しました","Payment to":"支払い先","Pending Confirmation":"承認待ち","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"永久にこのウォレットを削除します。\n二度と取り戻せない行為ですのどご注意下さい。","Personal Wallet":"個人用ウォレット","Please enter the recovery phrase":"復元フレーズをご入力下さい","Please enter the required fields":"必須項目をご入力下さい","Please enter the wallet recovery phrase":"復元フレーズをご入力下さい","Please tap the words in order to confirm your backup phrase is correctly written.":"正しい順番に単語をタップして、ちゃんと書き留めてあることをご確認下さい。","Please upgrade Copay to perform this action":"この操作を実行するにはCopayを最新バージョンに更新してください","Please wait to be redirected...":"ページが切り替わるまでお待ちください...","Please, select your backup file":"バックアップファイルを選択","Polish":"ポーランド語","Preferences":"設定","Preparing backup...":"バックアップを準備中...","preparing...":"準備中...","Press again to exit":"もう一度押して終了","Priority":"優先","Private key is encrypted, cannot sign":"秘密鍵が暗号化されており署名できません。","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Copayのプッシュ通知は現在無効です。アプリ設定で有効にします。","QR Code":"QRコード","QR-Scanner":"QRコードを読み取って下さい","Receive":"受取","Received":"受取済み","Recipients":"受取人","Recovery Phrase":"復元フレーズ","Recovery phrase deleted":"復元フレーズ削除済み","Recreate":"再登録","Recreating Wallet...":"ウォレットを再作成中…","Reject":"却下","Release Information":"リリース情報","Remove":"削除","Repeat password":"パスワードを再入力","Repeat the password":"パスワードの再入力","Repeat the spending password":"パスワードの再入力","Request a specific amount":"指定金額を要求","Request Spending Password":"送金時のパスワード入力","Required":"入力必須","Required number of signatures":"必要な署名の数を選択","Retrieving inputs information":"入力情報の取得中","Russian":"ロシア語","Save":"保存","Scan addresses for funds":"アドレスの残高照会","Scan Fingerprint":"指紋スキャン","Scan Finished":"スキャン完了","Scan status finished with error":"スキャンがエラーに終わりました","Scan Wallet Funds":"ウォレット残高照会","Scan your fingerprint please":"指紋をスキャンしてください","Scanning Wallet funds...":"ウォレット残高照会中…","Search transactions":"取引を検索","Search Transactions":"取引を検索","Security preferences":"セキュリティ設定","See it on the blockchain":"ブロックチェーンで詳細を閲覧","Select a backup file":"バックアップファイルを選択","Select a wallet":"ウォレットを選択","Self-signed Certificate":"自己署名証明書","Send":"送信","Send addresses by email":"ビットコインアドレスをメールにて共有","Send bitcoin":"ビットコインを送金","Send by email":"メールで送信","Send Max":"最大額を送金","Sending":"送信中","Sending transaction":"取引送信中","Sent":"送金済み","Server response could not be verified":"サーバーからの返答を検証できませんでした","Session log":"セッションのログ","SET":"指定","Set default url":"デフォルトURLに設定","Set up a password":"パスワードを設定","Set up a spending password":"パスワードを設定","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"メールのお知らせを有効にすると、悪意のあるサーバー運用者ならあなたの全てのアドレスとそれぞれの残高・履歴情報が把握できプライバシーの侵害に繋がる可能性があります。","Settings":"設定","Share address":"アドレスを共有","Share invitation":"招待コードを共有","Share this invitation with your copayers":"ウォレット参加者に\nこの招待コードを\n送って下さい。","Share this wallet address to receive payments":"送金を受けるためにはこのウォレットアドレスを共有して下さい。","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"これを人に共有することでビットコインを送ってもらうことができます。プライバシー向上の観点から、アドレスが1回でも使用されたら新しいアドレスが自動生成されます。","Shared Wallet":"共有ウォレットに参加","Show advanced options":"詳細設定を表示","Signatures rejected by server":"サーバーより署名が却下されました。","Signing transaction":"取引署名中","Single Address Wallet":"単一アドレスウォレット","Spanish":"スペイン語","Specify Recovery Phrase...":"復元フレーズを指定…","Spend proposal is not accepted":"送金の提案が受諾されませんでした。","Spend proposal not found":"送金の提案が見つかりませんでした。","Spending Password needed":"パスワードが必要","Spending Passwords do not match":"パスワードが一致しません","Success":"成功","Super Economy":"超節約","Sweep paper wallet":"ペーパーウォレットの全残高インポート","Sweep Wallet":"ウォレットの全残高インポート","Sweeping Wallet...":"ビットコイン回収中…","Tap and hold to show":"長押しで表示","Tap to retry":"タップしてやり直し","Terms of Use":"利用規約","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"このソフトの開発者、BitPayの従業員とその関係者、著作権所有者、BitPay, Inc. 自体もパスワード・秘密鍵・パスワードなどへのアクセスが不可能なため、教えることがだきません、なお、ビットコインのネットワークへの影響が無いので、取引の取り消しや優先的な承認などはできません。","The derivation path":"派生パス","The Ledger Chrome application is not installed":"Ledgerのクロームアプリがインストールされていません。","The password of the recovery phrase (if set)":"復元フレーズ用のパスワード(設定してある場合のみ)","The payment was created but could not be completed. Please try again from home screen":"送金の提案は作成されましたが完了できませんでした。ホーム画面からやり直して下さい。","The payment was removed by creator":"送金の提案が作成者により削除されました","The recovery phrase could require a password to be imported":"復元フレーズにパスワードをかけることができるのでかけてある場合はインポート時に必要です。","The request could not be understood by the server":"サーバーが要求を処理できませんでした。","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"BitPay, Inc. 若しくはその他の第三者がアクセス権限を管理する、若しくはデジタル資産の代理保管を行うサービスではありません。","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"当ソフトウェアは無料のオープンソースプロジェクトで、マルチシグネチャを用いるデジタルウォレットです。","The spend proposal is not pending":"送金の提案が協議中ではありません。","The wallet \"{{walletName}}\" was deleted":"ウォレット \"{{walletName}}\" が削除されました","The Wallet Recovery Phrase could require a password to be imported":"復元フレーズにパスワードをかけることができるのでかけてある場合はインポート時に必要です。","The wallet service URL":"ウォレットサービスのURL","There are no wallets to make this payment":"送金可能なウォレットがありません","There is a new version of Copay. Please update":"Copay の新しいバージョンがあります。更新してください。","There is an error in the form":"フォームにエラーがありました","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"この復元フレーズにパスワードがかかっています。このウォレットを復元するためには、復元フレーズに加え、パスワードも必要です。","This transaction has become invalid; possibly due to a double spend attempt.":"この取引が無効になりました。二重払いの可能性があります。","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"現在設定中のBitcore Wallet Service (BWS) サーバーにて、このウォレットの登録がありません。再登録を行うこともできます。","Time":"時刻","To":"宛先","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"この {{index.m}}-of-{{index.n}} 共有ウォレットを復元するに必要なものは","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"このソフトはそのままの提供となり、このソフトの利用に関わるあらゆる責任とリスクを自己責任で被り、利用するものとし、いかなる損害が発生しても、このソフトの開発者、BitPayの従業員とその関係者、著作権所有者、BitPay, Inc. 自体も責任を求めることは無いと誓います。","too long!":"長すぎます!","Total Locked Balance":"ロック中の残高","Total number of copayers":"参加人数を選択して下さい。","Touch ID Failed":"Touch ID が失敗しました。","Transaction":"取引","Transaction already broadcasted":"取引は既に配信されました。","Transaction History":"取引履歴","Translation Credits":"翻訳ボランティアの皆さん","Translators":"翻訳者","Try again":"もう一度やり直してください。","Type the Recovery Phrase (usually 12 words)":"復元フレーズの単語 (通常 12 個) を入力して下さい。","Unconfirmed":"未承認","Unit":"単位","Unsent transactions":"未送信取引","Updating transaction history. Please stand by.":"取引履歴を更新します。しばらくお待ちください。","Updating Wallet...":"ウォレット更新中…","Use Unconfirmed Funds":"未承認ビットコインを使用","Validating recovery phrase...":"復元フレーズを検証中…","Validating wallet integrity...":"ウォレットの整合性を検証中...","Version":"バージョン","View":"表示","Waiting for copayers":"ウォレット参加者を待っています","Waiting for Ledger...":"Ledger を待っています...","Waiting for Trezor...":"Trezor を待っています...","Waiting...":"少々お待ち下さい…","Wallet already exists":"既存のウォレットです","Wallet already in Copay":"Copay内の既存のウォレットです","Wallet Configuration (m-n)":"ウォレット構成 (m-of-n)","Wallet Export":"ウォレットのエクスポート","Wallet Id":"ウォレットID","Wallet incomplete and broken":"ウォレットが未完成で破損しています","Wallet Information":"ウォレット詳細","Wallet Invitation":"ウォレット招待","Wallet Invitation is not valid!":"ウォレット招待コードが無効です!","Wallet is full":"ウォレットがいっぱいです。","Wallet is locked":"ウォレットがロックされています。","Wallet is not complete":"ウォレットが未完成です。","Wallet name":"ウォレット名","Wallet Name (at creation)":"ウォレット名 (作成時)","Wallet needs backup":"ウォレットバックアップが必要","Wallet Network":"ウォレットのネットワーク","Wallet not found":"ウォレットが見つかりません。","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"このウォレットは Wallet Service にて登録されていません。再び「新規作成」メニューから詳細設定を選び、復元フレーズをご入力下さい。","Wallet Preferences":"ウォレット個別設定","Wallet Recovery Phrase":"復元フレーズ","Wallet Recovery Phrase is invalid":"ウォレットシードが不正です。","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"ウォレットの復元フレーズがありません。バックアップファイルの作成は「上級者向け」⇒「エクスポート」からアクセスできます。","Wallet service not found":"Wallet serviceが見つかりません。","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"注意:このデバイスでは鍵の派生がちゃんと動いておりません。このウォレットは正常に動作しません。","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"注意:このウォレットは秘密鍵がありません。残高の確認、取引履歴の確認、送金の提案ができます。しかし、送金の提案を承諾 (署名) できません。","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"注意:パスワードを復元することができませんしリセットできません。絶対に忘れないようにしてください。パスワードなしにこのバックアップファイルを復元することはできません。","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"注意:このウォレットは秘密鍵がありません。残高の確認、取引履歴の確認、送金の提案ができます。しかし、送金の提案を承諾 (署名) できません。","Warning: this transaction has unconfirmed inputs":"注意: この取引は未承認資金が含まれており、承認されるまで商品等をお渡しするのを待つことをお勧めします。","WARNING: UNTRUSTED CERTIFICATE":"警告: 信頼されていない証明書","WARNING: Wallet not registered":"注意:ウォレットが未登録","Warning!":"注意!","We reserve the right to modify this disclaimer from time to time.":"下記に英語の規約がありますので、英語が理解できる方は是非熟読して下さい。","WELCOME TO COPAY":"ようこそ COPAY へ","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"このソフトは長いテスト期間を経てリリースしましたが、今後バグや不具合が見つからないという保障はございません。","Write your wallet recovery phrase":"復元フレーズを書き留めて下さい","Wrong number of recovery words:":"単語の数が間違っています:","Wrong spending password":"不正なパスワード","Yes":"はい","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"この規約に同意することで、自己責任で利用するものとし、このソフトを用いてお住まいの地域の法令の違反はしないことを意味します。","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"このソフトを正常に利用するために必要なパスワード、秘密鍵、暗証番号などの秘密情報は自己責任で管理するものとします。","You assume any and all risks associated with the use of the software.":"この規約の言葉や表現のニュアンスによる解釈が必要となった場合、規約の元である英語のものを正とします。","You backed up your wallet. You can now restore this wallet at any time.":"新しいウォレットを正常にバックアップできました。いつでもこのウォレットが復元できます。","You can safely install your wallet on another device and use it from multiple devices at the same time.":"安全にウォレットを別のデバイスにインポートして、同じウォレットを複数の端末でご利用いただけます。","You do not have any wallet":"ウォレットがありません","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"この個人用ウォレットを復元するには復元フレーズが必要です。紙などに書き留めておき、安全な場所で保管して下さい。","Your nickname":"自分のハンドルネーム","Your password":"パスワード","Your spending password":"送金時のパスワード","Your wallet has been imported correctly":"ウォレットが正常にインポートされました。","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"ウォレットの鍵が暗号化されます。Copayでは送金時のパスワードをリセットしてくれる機能がありませんので、パスワードを忘れないよう、控えておいて下さい。","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"ウォレットの復元フレーズとそのウォレットが登録してあるサーバーへのアクセスが最低条件です。ただし、送金完了させるにはまだ {{index.m}} 個の鍵が他の参加者の間で持っていないといけませんので、他の参加者のバックアップも合わせてご確認下さい。"}); - gettextCatalog.setStrings('ko', {"(possible double spend)":"(이중 사용 가능성 있음)","(Trusted)":"(Trusted)","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} will be deducted for bitcoin networking fees","{{index.m}}-of-{{index.n}}":"{{index.m}}-of-{{index.n}}","{{item.m}}-of-{{item.n}}":"{{item.m}}-of-{{item.n}}","{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance":"{{len}} 개의 지갑을 가져왔습니다. 잔액을 조회하고 있습니다. 갱신된 잔액을 확인하려면 기다려 주세요","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* 지불제안은 다음 조건이 만족할 때 지울 수 있습니다. 1) 당신이 작성자이고, 다른 지갑 참여자가 사인하지 않았을 때, 또는 2) 제안이 작성된 지 24시간 이상이 지났을 때.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.","OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).":"OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).","OR the wallet seed of all copayers in the wallet":"OR the wallet seed of all copayers in the wallet","OR the wallet seeds of all copayers in the wallet":"OR the wallet seeds of all copayers in the wallet","A multisignature bitcoin wallet":"다중서명 비트코인 지갑","About Copay":"Copay에 대하여","Accept":"승인","Add a Seed Passphrase":"Add a Seed Passphrase","Add an optional passphrase to secure the seed":"Add an optional passphrase to secure the seed","Add wallet":"지갑 추가","Address":"주소","Address Type":"Address Type","Advanced":"고급","Advanced Send":"Advanced Send","Agree":"동의","Alias for {{index.walletName}}":"{{index.walletName}}의 별명","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at","All transaction requests are irreversible.":"All transaction requests are irreversible.","Already have a wallet?":"이미 지갑을 가지고 있나요?","Alternative Currency":"표시 통화","Amount":"금액","Amount below dust threshold":"Amount below dust threshold","Amount in":"Amount in","Applying changes":"변경 사항 적용 중","Are you sure you want to delete the backup words?":"Are you sure you want to delete the backup words?","Are you sure you want to delete this wallet?":"정말로 지갑을 삭제하시겠습니까?","Available Balance":"사용 가능한 잔액","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Average confirmation time: {{fee.nbBlocks * 10}} minutes","Back":"뒤로","Backup":"백업","Backup now":"지금 백업","Backup words deleted":"Backup words deleted","Bad wallet invitation":"Bad wallet invitation","Balance By Address":"Balance By Address","Before receiving funds, it is highly recommended you backup your wallet keys.":"비트코인을 받기 전에 지갑의 키를 백업하길 강력히 권장합니다.","Bitcoin address":"비트코인 주소","Bitcoin Network Fee Policy":"비트코인 네트워크 수수료 설정","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.":"Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.","Bitcoin URI is NOT valid!":"비트코인 URI가 유효하지 않습니다!","Broadcast Payment":"Broadcast Payment","Broadcasting Payment":"결제 전송 중","Broadcasting transaction":"Broadcasting transaction","Browser unsupported":"지원되지 않는 브라우저","Cancel":"취소","CANCEL":"취소","Cannot join the same wallet more that once":"Cannot join the same wallet more that once","Certified by":"Certified by","Changing wallet alias only affects the local wallet name.":"Changing wallet alias only affects the local wallet name.","Choose a backup file from your computer":"컴퓨터에서 백업 파일을 골라주세요","Choose a wallet to send funds":"돈을 보낼 지갑을 선택해주세요","Close":"닫기","Color":"색상","Commit hash":"커밋 해시","Confirm":"Confirm","Confirmations":"승인횟수","Connecting to {{create.hwWallet}} Wallet...":"Connecting to {{create.hwWallet}} Wallet...","Connecting to {{import.hwWallet}} Wallet...":"Connecting to {{import.hwWallet}} Wallet...","Connecting to {{join.hwWallet}} Wallet...":"Connecting to {{join.hwWallet}} Wallet...","Copayer already in this wallet":"Copayer already in this wallet","Copayer already voted on this spend proposal":"Copayer already voted on this spend proposal","Copayer data mismatch":"Copayer data mismatch","Copayers":"Copayers","Copied to clipboard":"Copied to clipboard","Copy this text as it is to a safe place (notepad or email)":"이 텍스트를 있는 그대로 복사해두세요(메모장이나 이메일등으로)","Copy to clipboard":"클립보드에 복사","Could not accept payment":"Could not accept payment","Could not access Wallet Service: Not found":"Could not access Wallet Service: Not found","Could not broadcast payment":"Could not broadcast payment","Could not create address":"Could not create address","Could not create payment proposal":"Could not create payment proposal","Could not create using the specified extended private key":"Could not create using the specified extended private key","Could not create using the specified extended public key":"Could not create using the specified extended public key","Could not create: Invalid wallet seed":"Could not create: Invalid wallet seed","Could not decrypt":"Could not decrypt","Could not decrypt file, check your password":"Could not decrypt file, check your password","Could not delete payment proposal":"Could not delete payment proposal","Could not fetch payment information":"Could not fetch payment information","Could not fetch transaction history":"거래내역을 가져올 수 없습니다","Could not import":"Could not import","Could not import. Check input file and password":"가져올 수 없습니다. 파일과 패스워드를 확인해 주세요","Could not join wallet":"Could not join wallet","Could not recognize a valid Bitcoin QR Code":"유효한 비트코인 QR코드를 인식할 수 없었습니다","Could not reject payment":"Could not reject payment","Could not send payment":"Could not send payment","Could not update Wallet":"지갑을 업데이트할 수 없습니다","Create":"작성","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"{{requiredCopayers}}-of-{{totalCopayers}} 지갑 만들기","Create new wallet":"새로운 지갑 만들기","Create, join or import":"만들기, 참가하기, 불러오기","Created by":"작성자","Creating Profile...":"프로필 만드는 중..","Creating transaction":"Creating transaction","Creating Wallet...":"지갑 만드는 중...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB","Date":"날짜","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.","Delete it and create a new one":"이 지갑을 삭제하고 새로운 지갑 만들기","Delete Payment Proposal":"지불제안 삭제","Delete wallet":"지갑 삭제","Delete Wallet":"지갑 삭제","DELETE WORDS":"DELETE WORDS","Deleting payment":"Deleting payment","Derivation Strategy":"Derivation Strategy","Details":"상세","Disabled":"Disabled","Do not include private key":"Do not include private key","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.","Download":"Download","Download CSV file":"CSV 파일 다운로드","Economy":"Economy","Email":"Email","Email for wallet notifications":"Email for wallet notifications","Email Notifications":"이메일 알림","Encrypted export file saved":"Encrypted export file saved","Enter the seed words (BIP39)":"Enter the seed words (BIP39)","Enter your password":"패스워드를 입력해주세요","Error at Wallet Service":"Error at Wallet Service","Error creating wallet":"지갑 생성 중 오류","Error importing wallet:":"지갑 가져오는 중 오류","Expires":"Expires","Export":"Export","Export options":"Export options","Extended Public Keys":"Extended Public Keys","External Private Key:":"External Private Key:","Failed to export":"Failed to export","Failed to import wallets":"지갑 가져오기 실패","Family vacation funds":"가족 휴가 자금","Fee":"수수료","Fee Policy":"Fee Policy","Fee policy for this transaction":"Fee policy for this transaction","Fetching Payment Information":"Fetching Payment Information","File/Text Backup":"File/Text Backup","French":"French","Funds are locked by pending spend proposals":"Funds are locked by pending spend proposals","Funds found":"Funds found","Funds received":"Funds received","Funds will be transfered to":"Funds will be transfered to","Generate new address":"새로운 주소 생성","Generate QR Code":"Generate QR Code","Generating .csv file...":".csv 파일 생성중...","German":"German","GET STARTED":"시작하기","Getting address for wallet {{selectedWalletName}} ...":"'{{selectedWalletName}}' 지갑의 주소 얻는 중...","Global settings":"전역 설정","Go back":"뒤로 가기","Greek":"Greek","Hardware wallet":"Hardware wallet","Hardware Wallet":"Hardware Wallet","Have a Backup from Copay v0.9?":"Copay v0.9용 백업을 가지고 계신가요?","Hide advanced options":"Hide advanced options","Hide Wallet Seed":"Hide Wallet Seed","History":"내역","Home":"홈","I affirm that I have read, understood, and agree with these terms.":"I affirm that I have read, understood, and agree with these terms.","Import":"가져오기","Import backup":"백업 가져오기","Import from Ledger":"Import from Ledger","Import from the Cloud?":"클라우드에서 가져올까요?","Import from TREZOR":"Import from TREZOR","Import here":"Import here","Import wallet":"지갑 가져오기","Importing wallet...":"지갑 가져오는 중...","Importing...":"가져오는 중...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.","Incorrect address network":"Incorrect address network","Insufficient funds":"Insufficient funds","Insufficient funds for fee":"Insufficient funds for fee","Invalid":"Invalid","Invalid address":"Invalid address","Invitation to share a Copay Wallet":"Invitation to share a Copay Wallet","Italian":"Italian","Japanese":"Japanese","John":"John","Join":"참가","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io","Join shared wallet":"공유지갑에 참가","Joining Wallet...":"지갑에 참가하는 중...","Key already associated with an existing wallet":"Key already associated with an existing wallet","Language":"언어","Last Wallet Addresses":"Last Wallet Addresses","Learn more about Copay backups":"Learn more about Copay backups","Learn more about Wallet Migration":"지갑 이동에 대해 더 알아보기","Loading...":"Loading...","locked by pending payments":"locked by pending payments","Locktime in effect. Please wait to create a new spend proposal":"Locktime in effect. Please wait to create a new spend proposal","Locktime in effect. Please wait to remove this spend proposal":"Locktime in effect. Please wait to remove this spend proposal","Make a payment to":"Make a payment to","me":"me","Me":"나","Memo":"메모","Merchant message":"Merchant message","Message":"메시지","More":"More","Moved":"Moved","Multisignature wallet":"다중서명 지갑","My Bitcoin address":"나의 비트코인 주소","Network":"네트워크","Network connection error":"Network connection error","New Payment Proposal":"새 지불제안","No Private key":"No Private key","No transactions yet":"No transactions yet","Normal":"Normal","Not authorized":"Not authorized","Not valid":"Not valid","Note":"메모","Official English Disclaimer":"Official English Disclaimer","Once you have copied your wallet seed down, it is recommended to delete it from this device.":"Once you have copied your wallet seed down, it is recommended to delete it from this device.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.","optional":"선택사항","Paper Wallet Private Key":"Paper Wallet Private Key","Participants":"참가자","Passphrase":"Passphrase","Passphrase (if you have one)":"Passphrase (if you have one)","Password":"Password","Password needed":"비밀번호가 필요합니다","Passwords do not match":"비밀번호가 일치하지 않습니다","Paste invitation here":"Paste invitation here","Paste the backup plain text code":"Paste the backup plain text code","Paste your paper wallet private key here":"Paste your paper wallet private key here","Pay To":"Pay To","Payment Accepted":"Payment Accepted","Payment accepted, but not yet broadcasted":"Payment accepted, but not yet broadcasted","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.","Payment details":"Payment details","Payment Proposal":"지불제안","Payment Proposal Created":"Payment Proposal Created","Payment Proposal Rejected":"Payment Proposal Rejected","Payment Proposal Rejected by Copayer":"Payment Proposal Rejected by Copayer","Payment Proposal Signed by Copayer":"Payment Proposal Signed by Copayer","Payment Proposals":"지불제안","Payment Protocol Invalid":"Payment Protocol Invalid","Payment Protocol not supported on Chrome App":"Payment Protocol not supported on Chrome App","Payment rejected":"Payment rejected","Payment Rejected":"Payment Rejected","Payment request":"Payment request","Payment sent":"Payment sent","Payment Sent":"Payment Sent","Payment to":"Payment to","Pending Confirmation":"Pending Confirmation","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED","Personal Wallet":"Personal Wallet","Please enter the required fields":"Please enter the required fields","Please enter the seed words":"Please enter the seed words","Please enter the wallet seed":"Please enter the wallet seed","Please upgrade Copay to perform this action":"Please upgrade Copay to perform this action","Please, select your backup file":"Please, select your backup file","Portuguese":"Portuguese","Preferences":"Preferences","Preparing backup...":"Preparing backup...","Priority":"Priority","QR Code":"QR코드","QR-Scanner":"QR스캐너","Receive":"Receive","Received":"Received","Recipients":"Recipients","Reconnecting to Wallet Service...":"Reconnecting to Wallet Service...","Recreate":"Recreate","Recreating Wallet...":"Recreating Wallet...","Reject":"거절","Rejecting payment":"Rejecting payment","Release Information":"Release Information","Repeat password":"패스워드 다시 입력","Request a specific amount":"Request a specific amount","Request Password for Spending Funds":"Request Password for Spending Funds","Requesting Ledger Wallet to sign":"Requesting Ledger Wallet to sign","Required":"Required","Required number of signatures":"Required number of signatures","Retrying...":"다시 시도 중...","Russian":"Russian","Save":"Save","Saving preferences...":"Saving preferences...","Scan addresses for funds":"Scan addresses for funds","Scan Finished":"Scan Finished","Scan status finished with error":"Scan status finished with error","Scan Wallet Funds":"Scan Wallet Funds","Scanning wallet funds...":"Scanning wallet funds...","Scanning Wallet funds...":"Scanning Wallet funds...","See it on the blockchain":"블록체인에서 보기","Seed passphrase":"Seed passphrase","Seed Passphrase":"Seed Passphrase","Select a backup file":"백업 파일 선택","Select a wallet":"Select a wallet","Self-signed Certificate":"Self-signed Certificate","Send":"Send","Send All":"Send All","Send all by email":"Send all by email","Send by email":"Send by email","Sending funds...":"Sending funds...","Sent":"Sent","Server":"서버","Server response could not be verified":"Server response could not be verified","Session log":"세션 로그","SET":"SET","Set up a Export Password":"Set up a Export Password","Set up a password":"패스워드 설정","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.","settings":"설정","Share address":"Share address","Share invitation":"Share invitation","Share this invitation with your copayers":"Share this invitation with your copayers","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.","Shared Wallet":"공유 지갑","Show advanced options":"Show advanced options","Show Wallet Seed":"Show Wallet Seed","Signatures rejected by server":"Signatures rejected by server","Signing payment":"Signing payment","SKIP BACKUP":"백업 건너뛰기","Spanish":"Spanish","Specify your wallet seed":"Specify your wallet seed","Spend proposal is not accepted":"Spend proposal is not accepted","Spend proposal not found":"Spend proposal not found","Still not done":"Still not done","Success":"성공","Sweep paper wallet":"Sweep paper wallet","Sweep Wallet":"Sweep Wallet","Tap to retry":"Tap to retry","Terms of Use":"이용약관","Testnet":"Testnet","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.","The Ledger Chrome application is not installed":"The Ledger Chrome application is not installed","The payment was created but could not be completed. Please try again from home screen":"The payment was created but could not be completed. Please try again from home screen","The payment was created but could not be signed. Please try again from home screen":"The payment was created but could not be signed. Please try again from home screen","The payment was removed by creator":"The payment was removed by creator","The payment was signed but could not be broadcasted. Please try again from home screen":"The payment was signed but could not be broadcasted. Please try again from home screen","The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.":"The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.","The seed could require a passphrase to be imported":"The seed could require a passphrase to be imported","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"The software you are about to use functions as a free, open source, and multi-signature digital wallet.","The spend proposal is not pending":"The spend proposal is not pending","The wallet \"{{walletName}}\" was deleted":"The wallet \"{{walletName}}\" was deleted","There are no wallets to make this payment":"There are no wallets to make this payment","There is an error in the form":"There is an error in the form","This transaction has become invalid; possibly due to a double spend attempt.":"This transaction has become invalid; possibly due to a double spend attempt.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.","Time":"시간","To":"To","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"To restore this {{index.m}}-{{index.n}} shared wallet you will need","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.","too long!":"너무 깁니다!","Total":"Total","Total Locked Balance":"Total Locked Balance","Total number of copayers":"Total number of copayers","Transaction":"Transaction","Transaction already broadcasted":"Transaction already broadcasted","Translation Credits":"Translation Credits","Translators":"Translators","Type the Seed Word (usually 12 words)":"Type the Seed Word (usually 12 words)","Unable to send transaction proposal":"Unable to send transaction proposal","Unconfirmed":"Unconfirmed","Unit":"단위","Unsent transactions":"Unsent transactions","Updating Wallet...":"Updating Wallet...","Use Ledger hardware wallet":"Use Ledger hardware wallet","Use TREZOR hardware wallet":"Use TREZOR hardware wallet","Use Unconfirmed Funds":"Use Unconfirmed Funds","Username":"Username","Version":"버전","View":"View","Waiting for copayers":"Waiting for copayers","Waiting...":"대기 중...","Wallet":"Wallet","Wallet Alias":"지갑 별명","Wallet already exists":"이미 존재하는 지갑입니다","Wallet Already Imported:":"이미 가져온 지갑:","Wallet already in Copay:":"Wallet already in Copay:","Wallet Configuration (m-n)":"Wallet Configuration (m-n)","Wallet Export":"Wallet Export","Wallet Id":"Wallet Id","Wallet incomplete and broken":"Wallet incomplete and broken","Wallet Information":"Wallet Information","Wallet Invitation":"지갑 초대","Wallet Invitation is not valid!":"지갑 초대가 유효하지 않습니다!","Wallet is full":"Wallet is full","Wallet is not complete":"Wallet is not complete","Wallet name":"지갑 이름","Wallet Name (at creation)":"Wallet Name (at creation)","Wallet Network":"Wallet Network","Wallet not found":"Wallet not found","Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed":"Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed","Wallet Seed":"Wallet Seed","Wallet Seed could require a passphrase to be imported":"Wallet Seed could require a passphrase to be imported","Wallet seed is invalid":"Wallet seed is invalid","Wallet seed not available. You can still export it from Advanced > Export.":"Wallet seed not available. You can still export it from Advanced > Export.","Wallet service not found":"Wallet service not found","WARNING: Backup needed":"경고: 백업이 필요합니다","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.":"WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.":"WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.","Warning: this transaction has unconfirmed inputs":"Warning: this transaction has unconfirmed inputs","WARNING: UNTRUSTED CERTIFICATE":"WARNING: UNTRUSTED CERTIFICATE","WARNING: Wallet not registered":"WARNING: Wallet not registered","Warning!":"경고!","We reserve the right to modify this disclaimer from time to time.":"We reserve the right to modify this disclaimer from time to time.","WELCOME TO COPAY":"WELCOME TO COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.","Write it down and keep them somewhere safe.":"Write it down and keep them somewhere safe.","Wrong number of seed words:":"Wrong number of seed words:","Wrong password":"잘못된 비밀번호","Yes":"Yes","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.","You assume any and all risks associated with the use of the software.":"You assume any and all risks associated with the use of the software.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"You can safely install your wallet on another device and use it from multiple devices at the same time.","You do not have a wallet":"지갑이 없습니다","You need the wallet seed to restore this personal wallet.":"You need the wallet seed to restore this personal wallet.","Your backup password":"백업 패스워드","Your export password":"Your export password","Your nickname":"당신의 닉네임","Your password":"당신의 비밀번호","Your profile password":"프로필 패스워드","Your wallet has been imported correctly":"지갑을 정상적으로 가져왔습니다","Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down":"Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down","Your Wallet Seed":"Your Wallet Seed","Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend."}); - gettextCatalog.setStrings('nl', {"(possible double spend)":"(mogelijk dubbel besteed)","(Trusted)":"(Trusted)","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} will be deducted for bitcoin networking fees","{{index.m}}-of-{{index.n}}":"{{index.m}}-of-{{index.n}}","{{item.m}}-of-{{item.n}}":"{{item.m}}-of-{{item.n}}","{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance":"{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Een betalingsvoorstel kan worden verwijderd als 1) u de aanmaker bent, en geen andere medebetaler heeft ondertekend, of 2) 24 uur zijn verstreken sinds het voorstel werd aangemaakt.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.","OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).":"OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).","OR the wallet seed of all copayers in the wallet":"OR the wallet seed of all copayers in the wallet","OR the wallet seeds of all copayers in the wallet":"OR the wallet seeds of all copayers in the wallet","A multisignature bitcoin wallet":"A multisignature bitcoin wallet","About Copay":"About Copay","Accept":"Accept","Add a Seed Passphrase":"Add a Seed Passphrase","Add an optional passphrase to secure the seed":"Add an optional passphrase to secure the seed","Add wallet":"Add wallet","Address":"Address","Address Type":"Address Type","Advanced":"Advanced","Advanced Send":"Advanced Send","Agree":"Agree","Alias for {{index.walletName}}":"Alias for {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at","All transaction requests are irreversible.":"All transaction requests are irreversible.","Already have a wallet?":"Already have a wallet?","Alternative Currency":"Alternative Currency","Amount":"Amount","Amount below dust threshold":"Amount below dust threshold","Amount in":"Amount in","Applying changes":"Applying changes","Are you sure you want to delete the backup words?":"Are you sure you want to delete the backup words?","Are you sure you want to delete this wallet?":"Are you sure you want to delete this wallet?","Available Balance":"Available Balance","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Average confirmation time: {{fee.nbBlocks * 10}} minutes","Back":"Back","Backup":"Backup","Backup now":"Backup now","Backup words deleted":"Backup words deleted","Bad wallet invitation":"Bad wallet invitation","Balance By Address":"Balance By Address","Before receiving funds, it is highly recommended you backup your wallet keys.":"Before receiving funds, it is highly recommended you backup your wallet keys.","Bitcoin address":"Bitcoin address","Bitcoin Network Fee Policy":"Bitcoin Network Fee Policy","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.":"Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.","Bitcoin URI is NOT valid!":"Bitcoin URI is NOT valid!","Broadcast Payment":"Broadcast Payment","Broadcasting Payment":"Broadcasting Payment","Broadcasting transaction":"Broadcasting transaction","Browser unsupported":"Browser unsupported","Cancel":"Cancel","CANCEL":"CANCEL","Cannot join the same wallet more that once":"Cannot join the same wallet more that once","Certified by":"Certified by","Changing wallet alias only affects the local wallet name.":"Changing wallet alias only affects the local wallet name.","Choose a backup file from your computer":"Choose a backup file from your computer","Choose a wallet to send funds":"Choose a wallet to send funds","Close":"Close","Color":"Color","Commit hash":"Commit hash","Confirm":"Confirm","Confirmations":"Confirmations","Connecting to {{create.hwWallet}} Wallet...":"Connecting to {{create.hwWallet}} Wallet...","Connecting to {{import.hwWallet}} Wallet...":"Connecting to {{import.hwWallet}} Wallet...","Connecting to {{join.hwWallet}} Wallet...":"Connecting to {{join.hwWallet}} Wallet...","Copayer already in this wallet":"Copayer already in this wallet","Copayer already voted on this spend proposal":"Copayer already voted on this spend proposal","Copayer data mismatch":"Copayer data mismatch","Copayers":"Copayers","Copied to clipboard":"Copied to clipboard","Copy this text as it is to a safe place (notepad or email)":"Copy this text as it is to a safe place (notepad or email)","Copy to clipboard":"Copy to clipboard","Could not accept payment":"Could not accept payment","Could not access Wallet Service: Not found":"Could not access Wallet Service: Not found","Could not broadcast payment":"Could not broadcast payment","Could not create address":"Could not create address","Could not create payment proposal":"Could not create payment proposal","Could not create using the specified extended private key":"Could not create using the specified extended private key","Could not create using the specified extended public key":"Could not create using the specified extended public key","Could not create: Invalid wallet seed":"Could not create: Invalid wallet seed","Could not decrypt":"Could not decrypt","Could not decrypt file, check your password":"Could not decrypt file, check your password","Could not delete payment proposal":"Could not delete payment proposal","Could not fetch payment information":"Could not fetch payment information","Could not fetch transaction history":"Could not fetch transaction history","Could not import":"Could not import","Could not import. Check input file and password":"Could not import. Check input file and password","Could not join wallet":"Could not join wallet","Could not recognize a valid Bitcoin QR Code":"Could not recognize a valid Bitcoin QR Code","Could not reject payment":"Could not reject payment","Could not send payment":"Could not send payment","Could not update Wallet":"Could not update Wallet","Create":"Create","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Create {{requiredCopayers}}-of-{{totalCopayers}} wallet","Create new wallet":"Create new wallet","Create, join or import":"Create, join or import","Created by":"Created by","Creating Profile...":"Creating Profile...","Creating transaction":"Creating transaction","Creating Wallet...":"Creating Wallet...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB","Date":"Date","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.","Delete it and create a new one":"Delete it and create a new one","Delete Payment Proposal":"Delete Payment Proposal","Delete wallet":"Delete wallet","Delete Wallet":"Delete Wallet","DELETE WORDS":"DELETE WORDS","Deleting payment":"Deleting payment","Derivation Strategy":"Derivation Strategy","Details":"Details","Disabled":"Disabled","Do not include private key":"Do not include private key","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.","Download":"Download","Download CSV file":"Download CSV file","Economy":"Economy","Email":"Email","Email for wallet notifications":"Email for wallet notifications","Email Notifications":"Email Notifications","Encrypted export file saved":"Encrypted export file saved","Enter the seed words (BIP39)":"Enter the seed words (BIP39)","Enter your password":"Enter your password","Error at Wallet Service":"Error at Wallet Service","Error creating wallet":"Error creating wallet","Error importing wallet:":"Error importing wallet:","Expires":"Expires","Export":"Export","Export options":"Export options","Extended Public Keys":"Extended Public Keys","External Private Key:":"External Private Key:","Failed to export":"Failed to export","Failed to import wallets":"Failed to import wallets","Family vacation funds":"Family vacation funds","Fee":"Fee","Fee Policy":"Fee Policy","Fee policy for this transaction":"Fee policy for this transaction","Fetching Payment Information":"Fetching Payment Information","File/Text Backup":"File/Text Backup","French":"French","Funds are locked by pending spend proposals":"Funds are locked by pending spend proposals","Funds found":"Funds found","Funds received":"Funds received","Funds will be transfered to":"Funds will be transfered to","Generate new address":"Generate new address","Generate QR Code":"Generate QR Code","Generating .csv file...":"Generating .csv file...","German":"German","GET STARTED":"GET STARTED","Getting address for wallet {{selectedWalletName}} ...":"Getting address for wallet {{selectedWalletName}} ...","Global settings":"Global settings","Go back":"Go back","Greek":"Greek","Hardware wallet":"Hardware wallet","Hardware Wallet":"Hardware Wallet","Have a Backup from Copay v0.9?":"Have a Backup from Copay v0.9?","Hide advanced options":"Hide advanced options","Hide Wallet Seed":"Hide Wallet Seed","History":"History","Home":"Home","I affirm that I have read, understood, and agree with these terms.":"I affirm that I have read, understood, and agree with these terms.","Import":"Import","Import backup":"Import backup","Import from Ledger":"Import from Ledger","Import from the Cloud?":"Import from the Cloud?","Import from TREZOR":"Import from TREZOR","Import here":"Import here","Import wallet":"Import wallet","Importing wallet...":"Importing wallet...","Importing...":"Importing...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.","Incorrect address network":"Incorrect address network","Insufficient funds":"Insufficient funds","Insufficient funds for fee":"Insufficient funds for fee","Invalid":"Invalid","Invalid address":"Invalid address","Invitation to share a Copay Wallet":"Invitation to share a Copay Wallet","Italian":"Italian","Japanese":"Japanese","John":"John","Join":"Join","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io","Join shared wallet":"Join shared wallet","Joining Wallet...":"Joining Wallet...","Key already associated with an existing wallet":"Key already associated with an existing wallet","Language":"Language","Last Wallet Addresses":"Last Wallet Addresses","Learn more about Copay backups":"Learn more about Copay backups","Learn more about Wallet Migration":"Learn more about Wallet Migration","Loading...":"Loading...","locked by pending payments":"locked by pending payments","Locktime in effect. Please wait to create a new spend proposal":"Locktime in effect. Please wait to create a new spend proposal","Locktime in effect. Please wait to remove this spend proposal":"Locktime in effect. Please wait to remove this spend proposal","Make a payment to":"Make a payment to","me":"me","Me":"Me","Memo":"Memo","Merchant message":"Merchant message","Message":"Message","More":"More","Moved":"Moved","Multisignature wallet":"Multisignature wallet","My Bitcoin address":"My Bitcoin address","Network":"Network","Network connection error":"Network connection error","New Payment Proposal":"New Payment Proposal","No Private key":"No Private key","No transactions yet":"No transactions yet","Normal":"Normal","Not authorized":"Not authorized","Not valid":"Not valid","Note":"Note","Official English Disclaimer":"Official English Disclaimer","Once you have copied your wallet seed down, it is recommended to delete it from this device.":"Once you have copied your wallet seed down, it is recommended to delete it from this device.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.","optional":"optional","Paper Wallet Private Key":"Paper Wallet Private Key","Participants":"Participants","Passphrase":"Passphrase","Passphrase (if you have one)":"Passphrase (if you have one)","Password":"Password","Password needed":"Password needed","Passwords do not match":"Passwords do not match","Paste invitation here":"Paste invitation here","Paste the backup plain text code":"Paste the backup plain text code","Paste your paper wallet private key here":"Paste your paper wallet private key here","Pay To":"Pay To","Payment Accepted":"Payment Accepted","Payment accepted, but not yet broadcasted":"Payment accepted, but not yet broadcasted","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.","Payment details":"Payment details","Payment Proposal":"Payment Proposal","Payment Proposal Created":"Payment Proposal Created","Payment Proposal Rejected":"Payment Proposal Rejected","Payment Proposal Rejected by Copayer":"Payment Proposal Rejected by Copayer","Payment Proposal Signed by Copayer":"Payment Proposal Signed by Copayer","Payment Proposals":"Payment Proposals","Payment Protocol Invalid":"Payment Protocol Invalid","Payment Protocol not supported on Chrome App":"Payment Protocol not supported on Chrome App","Payment rejected":"Payment rejected","Payment Rejected":"Payment Rejected","Payment request":"Payment request","Payment sent":"Payment sent","Payment Sent":"Payment Sent","Payment to":"Payment to","Pending Confirmation":"Pending Confirmation","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED","Personal Wallet":"Personal Wallet","Please enter the required fields":"Please enter the required fields","Please enter the seed words":"Please enter the seed words","Please enter the wallet seed":"Please enter the wallet seed","Please upgrade Copay to perform this action":"Please upgrade Copay to perform this action","Please, select your backup file":"Please, select your backup file","Portuguese":"Portuguese","Preferences":"Preferences","Preparing backup...":"Preparing backup...","Priority":"Priority","QR Code":"QR Code","QR-Scanner":"QR-Scanner","Receive":"Receive","Received":"Received","Recipients":"Recipients","Reconnecting to Wallet Service...":"Reconnecting to Wallet Service...","Recreate":"Recreate","Recreating Wallet...":"Recreating Wallet...","Reject":"Reject","Rejecting payment":"Rejecting payment","Release Information":"Release Information","Repeat password":"Repeat password","Request a specific amount":"Request a specific amount","Request Password for Spending Funds":"Request Password for Spending Funds","Requesting Ledger Wallet to sign":"Requesting Ledger Wallet to sign","Required":"Required","Required number of signatures":"Required number of signatures","Retrying...":"Retrying...","Russian":"Russian","Save":"Save","Saving preferences...":"Saving preferences...","Scan addresses for funds":"Scan addresses for funds","Scan Finished":"Scan Finished","Scan status finished with error":"Scan status finished with error","Scan Wallet Funds":"Scan Wallet Funds","Scanning wallet funds...":"Scanning wallet funds...","Scanning Wallet funds...":"Scanning Wallet funds...","See it on the blockchain":"See it on the blockchain","Seed passphrase":"Seed passphrase","Seed Passphrase":"Seed Passphrase","Select a backup file":"Select a backup file","Select a wallet":"Select a wallet","Self-signed Certificate":"Self-signed Certificate","Send":"Send","Send All":"Send All","Send all by email":"Send all by email","Send by email":"Send by email","Sending funds...":"Sending funds...","Sent":"Sent","Server":"Server","Server response could not be verified":"Server response could not be verified","Session log":"Session log","SET":"SET","Set up a Export Password":"Set up a Export Password","Set up a password":"Set up a password","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.","settings":"settings","Share address":"Share address","Share invitation":"Share invitation","Share this invitation with your copayers":"Share this invitation with your copayers","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.","Shared Wallet":"Shared Wallet","Show advanced options":"Show advanced options","Show Wallet Seed":"Show Wallet Seed","Signatures rejected by server":"Signatures rejected by server","Signing payment":"Signing payment","SKIP BACKUP":"SKIP BACKUP","Spanish":"Spanish","Specify your wallet seed":"Specify your wallet seed","Spend proposal is not accepted":"Spend proposal is not accepted","Spend proposal not found":"Spend proposal not found","Still not done":"Still not done","Success":"Success","Sweep paper wallet":"Sweep paper wallet","Sweep Wallet":"Sweep Wallet","Tap to retry":"Tap to retry","Terms of Use":"Terms of Use","Testnet":"Testnet","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.","The Ledger Chrome application is not installed":"The Ledger Chrome application is not installed","The payment was created but could not be completed. Please try again from home screen":"The payment was created but could not be completed. Please try again from home screen","The payment was created but could not be signed. Please try again from home screen":"The payment was created but could not be signed. Please try again from home screen","The payment was removed by creator":"The payment was removed by creator","The payment was signed but could not be broadcasted. Please try again from home screen":"The payment was signed but could not be broadcasted. Please try again from home screen","The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.":"The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.","The seed could require a passphrase to be imported":"The seed could require a passphrase to be imported","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"The software you are about to use functions as a free, open source, and multi-signature digital wallet.","The spend proposal is not pending":"The spend proposal is not pending","The wallet \"{{walletName}}\" was deleted":"The wallet \"{{walletName}}\" was deleted","There are no wallets to make this payment":"There are no wallets to make this payment","There is an error in the form":"There is an error in the form","This transaction has become invalid; possibly due to a double spend attempt.":"This transaction has become invalid; possibly due to a double spend attempt.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.","Time":"Time","To":"To","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"To restore this {{index.m}}-{{index.n}} shared wallet you will need","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.","too long!":"too long!","Total":"Total","Total Locked Balance":"Total Locked Balance","Total number of copayers":"Total number of copayers","Transaction":"Transaction","Transaction already broadcasted":"Transaction already broadcasted","Translation Credits":"Translation Credits","Translators":"Translators","Type the Seed Word (usually 12 words)":"Type the Seed Word (usually 12 words)","Unable to send transaction proposal":"Unable to send transaction proposal","Unconfirmed":"Unconfirmed","Unit":"Unit","Unsent transactions":"Unsent transactions","Updating Wallet...":"Updating Wallet...","Use Ledger hardware wallet":"Use Ledger hardware wallet","Use TREZOR hardware wallet":"Use TREZOR hardware wallet","Use Unconfirmed Funds":"Use Unconfirmed Funds","Username":"Username","Version":"Version","View":"View","Waiting for copayers":"Waiting for copayers","Waiting...":"Waiting...","Wallet":"Wallet","Wallet Alias":"Wallet Alias","Wallet already exists":"Wallet already exists","Wallet Already Imported:":"Wallet Already Imported:","Wallet already in Copay:":"Wallet already in Copay:","Wallet Configuration (m-n)":"Wallet Configuration (m-n)","Wallet Export":"Wallet Export","Wallet Id":"Wallet Id","Wallet incomplete and broken":"Wallet incomplete and broken","Wallet Information":"Wallet Information","Wallet Invitation":"Wallet Invitation","Wallet Invitation is not valid!":"Wallet Invitation is not valid!","Wallet is full":"Wallet is full","Wallet is not complete":"Wallet is not complete","Wallet name":"Wallet name","Wallet Name (at creation)":"Wallet Name (at creation)","Wallet Network":"Wallet Network","Wallet not found":"Wallet not found","Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed":"Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed","Wallet Seed":"Wallet Seed","Wallet Seed could require a passphrase to be imported":"Wallet Seed could require a passphrase to be imported","Wallet seed is invalid":"Wallet seed is invalid","Wallet seed not available. You can still export it from Advanced > Export.":"Wallet seed not available. You can still export it from Advanced > Export.","Wallet service not found":"Wallet service not found","WARNING: Backup needed":"WARNING: Backup needed","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.":"WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.":"WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.","Warning: this transaction has unconfirmed inputs":"Warning: this transaction has unconfirmed inputs","WARNING: UNTRUSTED CERTIFICATE":"WARNING: UNTRUSTED CERTIFICATE","WARNING: Wallet not registered":"WARNING: Wallet not registered","Warning!":"Warning!","We reserve the right to modify this disclaimer from time to time.":"We reserve the right to modify this disclaimer from time to time.","WELCOME TO COPAY":"WELCOME TO COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.","Write it down and keep them somewhere safe.":"Write it down and keep them somewhere safe.","Wrong number of seed words:":"Wrong number of seed words:","Wrong password":"Wrong password","Yes":"Yes","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.","You assume any and all risks associated with the use of the software.":"You assume any and all risks associated with the use of the software.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"You can safely install your wallet on another device and use it from multiple devices at the same time.","You do not have a wallet":"You do not have a wallet","You need the wallet seed to restore this personal wallet.":"You need the wallet seed to restore this personal wallet.","Your backup password":"Your backup password","Your export password":"Your export password","Your nickname":"Your nickname","Your password":"Your password","Your profile password":"Your profile password","Your wallet has been imported correctly":"Your wallet has been imported correctly","Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down":"Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down","Your Wallet Seed":"Your Wallet Seed","Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend."}); - gettextCatalog.setStrings('pl', {"(possible double spend)":"(możliwa podwójna wypłata)","(Trusted)":"(Zaufany)","[Balance Hidden]":"[Balans Ukryty]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} zostanie potrącone jako prowizja sieci bitcoin","{{feeRateStr}} of the transaction":"{{feeRateStr}} transakcji","{{index.m}}-of-{{index.n}}":"{{index.m}}-z-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} więcej","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} transakcji pobrane","{{item.m}}-of-{{item.n}}":"{{item.m}}-z-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Wniosek wypłaty może być usunięty jeśli: 1) Po utworzeniu nie zatwierdził go żaden inny współwłaściciel portfela lub 2) minęły 24 godziny od kiedy wniosek został utworzony.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"JEŚLI UŻYTKOWNIK STRACI DOSTĘP DO PORTFELA COPAY LUB ZASZYFROWANYCH KLUCZY PRYWATNYCH, A NIE MA ZAPISANEJ KOPII ZAPASOWEJ PORTFELA I HASŁA, PRZYJMUJE DO WIADOMOŚCI, ŻE JAKIEKOLWIEK POSIADANE BITCOINY ZWIĄZANE Z TYM PORTFELEM COPAY BĘDĄ NIEDOSTĘPNE.","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"LUB 1 plik eksportu portfela i reszta wymaganych fraz odzyskiwania portfela (np. w portfelu 3-5: 1 plik eksportu portfela + 2 frazy odzyskiwania któregokolwiek z pozostałych współwłaścicieli portfela).","OR the wallet recovery phrase of all copayers in the wallet":"LUB frazy odzyskiwania wszystkich współwłaścicieli portfela","OR the wallet recovery phrases of all copayers in the wallet":"LUB fraz odzyskiwania wszystkich współwłaścicieli portfela","A multisignature bitcoin wallet":"Portfel bitcoin z multipodpisami","About Copay":"Informacje o Copay","Accept":"Akceptuj","Account":"Konto","Account Number":"Numer konta","Activity":"Transakcje","Add a new entry":"Dodaj nowy wpis","Add a Password":"Dodaj hasło","Add an optional password to secure the recovery phrase":"Dodaj opcjonalne hasło do bezpiecznego odzyskiwania frazy","Add comment":"Dodaj komentarz","Add wallet":"Dodaj portfel","Address":"Adres","Address Type":"Rodzaj adresu","Advanced":"Zaawansowane","Alias":"Nazwa","Alias for {{index.walletName}}":"Nazwa dla {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Wkład do tłumaczenia Copay mile widziany. Zapisz się na crowdin.com i dołącz do projektu Copay na","All transaction requests are irreversible.":"Transakcji nie można wycofać.","Alternative Currency":"Alternatywna waluta","Amount":"Kwota","Amount below minimum allowed":"Kwota poniżej minimum dozwolona","Amount in":"Kwota w","Are you sure you want to delete the recovery phrase?":"Czy na pewno chcesz usunąć frazę?","Are you sure you want to delete this wallet?":"Czy na pewno chcesz usunąć ten portfel?","Auditable":"Weryfikowalny","Available Balance":"Dostępne saldo","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Średni czas potwierdzenia: {{fee.nbBlocks * 10}} minut","Back":"Powrót","Backup":"Kopia zapasowa","Backup failed":"Tworzenie kopii zapasowej nie powiodło się","Backup Needed":"Potrzebna kopia zapasowa","Backup now":"Utwórz kopię zapasową teraz","Bad wallet invitation":"Nieprawidłowe zaproszenie","Balance By Address":"Saldo wg adresu","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Przed otrzymaniem środków, konieczne jest wykonanie kopii zapasowej portfela. Jeśli utracisz to urządzenie, dostęp do funduszy bez kopii zapasowej będzie niemożliwy.","BETA: Android Key Derivation Test:":"BETA: Test Android Key Derivation:","BIP32 path for address derivation":"BIP32 ścieżka dla adresu derywacji","Bitcoin address":"Adres bitcoin","Bitcoin Network Fee Policy":"Polityka prowizji sieci bitcoin","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Transakcje bitcoinowe mogą zawierać prowizję pobieraną przez górników. Im wyższa prowizja, tym większa zachęta dla górnika, aby zawarł tę transakcję w bloku. Rzeczywiste opłaty ustala się w oparciu o obciążenie sieci i wybraną politykę.","Bitcoin URI is NOT valid!":"Bitcoin URI jest nieprawidłowy!","Broadcast Payment":"Przekaż płatność","Broadcasting transaction":"Przekazywanie transakcji","Browser unsupported":"Przeglądarka nieobsługiwana","Calculating fee":"Obliczanie prowizji","Cancel":"Anuluj","Cancel and delete the wallet":"Anuluj i usuń portfel","Cannot create transaction. Insufficient funds":"Nie można utworzyć transakcji. Niewystarczające fundusze","Cannot join the same wallet more that once":"Nie można dołączyć tego samego portfela więcej niż raz","Cannot sign: The payment request has expired":"Nie można podpisać: Wniosek wypłaty wygasł","Certified by":"Certyfikowane przez","Changing wallet alias only affects the local wallet name.":"Zmiana nazwy portfela wpływa tylko na jego nazwę lokalną.","Chinese":"chiński","Choose a backup file from your computer":"Wybierz plik kopii zapasowej z komputera","Clear cache":"Wyczyść pamięć podręczną","Close":"Zamknij","Color":"Kolor","Comment":"Skomentuj","Commit hash":"Zatwierdzony hash","Confirm":"Potwierdź","Confirm your wallet recovery phrase":"Potwierdź swoją frazę odzyskiwania portfela","Confirmations":"Potwierdzenia","Congratulations!":"Gratulacje!","Connecting to Coinbase...":"Łączenie z Coinbase...","Connecting to Glidera...":"Łączenie z Gildera...","Connection reset by peer":"Połączenie zostało zresetowane","Continue":"Dalej","Copayer already in this wallet":"Użytkownik jest już w tym portfelu","Copayer already voted on this spend proposal":"Użytkownik głosował już za tym wnioskiem wypłaty","Copayer data mismatch":"Niezgodność danych współwłaściciela portfela","Copayers":"Współwłaściciele portfela","Copied to clipboard":"Skopiowano do schowka","Copy this text as it is to a safe place (notepad or email)":"Skopiuj ten tekst w bezpiecznym miejscu (notatnik lub e-mail)","Copy to clipboard":"Skopiuj do schowka","Could not access the wallet at the server. Please check:":"Nie można uzyskać dostępu do portfela na serwerze. Proszę sprawdzić:","Could not access wallet":"Nie można uzyskać dostępu do portfela","Could not access Wallet Service: Not found":"Brak dostępu do Wallet Service: Nie znaleziono","Could not broadcast payment":"Wypłata nie może zostać wysłana","Could not build transaction":"Nie udało się utworzyć transakcji","Could not create address":"Nie można utworzyć adresu","Could not create payment proposal":"Nie można wygenerować wniosku wypłaty","Could not create using the specified extended private key":"Nie można utworzyć przy użyciu określonego rozszerzonego klucza prywatnego","Could not create using the specified extended public key":"Nie można utworzyć przy użyciu określonego rozszerzonego klucza publicznego","Could not create: Invalid wallet recovery phrase":"Nie można utworzyć: niepoprawna fraza odzyskiwania portfela","Could not decrypt file, check your password":"Nie można odszyfrować pliku, sprawdź hasło","Could not delete payment proposal":"Nie można usunąć wniosku wypłaty","Could not fetch payment information":"Informacje dotyczące wypłaty nie mogą zostać pobrane","Could not get fee value":"Nie można uzyskać kwoty prowizji","Could not import":"Nie można zaimportować","Could not import. Check input file and spending password":"Nie można zaimportować. Sprawdź plik wejściowy i hasło","Could not join wallet":"Nie można dołączyć portfela","Could not recognize a valid Bitcoin QR Code":"Nie udało się rozpoznać poprawnego kodu QR","Could not reject payment":"Wypłata nie może być odrzucona","Could not send payment":"Wypłata nie może zostać wysłana","Could not update Wallet":"Nie można zaktualizować portfela","Create":"Utwórz","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Utwórz portfel {{requiredCopayers}} z {{totalCopayers}}","Create new wallet":"Utwórz nowy portfel","Create, join or import":"Utwórz, dołącz lub importuj","Created by":"Utworzony przez","Creating transaction":"Tworzenie transakcji","Creating Wallet...":"Tworzenie portfela...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Obecna stawka prowizji dla tych ustawień: {{fee.feePerKBUnit}}/KiB","Czech":"czeski","Date":"Data","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Odszyfrowywanie papierowego portfela zajmie na tym urządzeniu około 5 minut. Prosimy o niezamykanie aplikacji.","Delete it and create a new one":"Usuń i utwórz nowy portfel","Delete Payment Proposal":"Usuń wniosek wypłaty","Delete recovery phrase":"Usuń frazę odzyskiwania","Delete Recovery Phrase":"Usuń Frazę Odzyskiwania","Delete wallet":"Usuń portfel","Delete Wallet":"Usuń portfel","Deleting Wallet...":"Usuwanie portfela...","Derivation Path":"Ścieżka derywacji","Derivation Strategy":"Strategia derywacji","Description":"Opis","Details":"Szczegóły","Disabled":"Wyłącz","Do not include private key":"Nie uwzględniaj klucza prywatnego","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Nie widzisz swojego języka na Crowdin? Skontaktuj się z właścicielem projektu, ponieważ bardzo chcielibyśmy, wspierać twój język.","Done":"Gotowe","Download":"Pobierz","Economy":"Ekonomiczna","Edit":"Edytuj","Edit comment":"Edytuj komentarz","Edited by":"Edytowane przez","Email for wallet notifications":"Adres e-mail dla powiadomień portfela","Email Notifications":"Powiadomienia e-mail","Empty addresses limit reached. New addresses cannot be generated.":"Puste adresy osiągnęły limit. Nowe adresy nie mogą być generowane.","Enable Coinbase Service":"Włącz usługę Coinbase","Enable Glidera Service":"Włącz usługę Glidera","Enable push notifications":"Włącz powiadomienia","Encrypted export file saved":"Zaszyfrowany plik eksportu zapisany","Enter the recovery phrase (BIP39)":"Wprowadź frazę odzyskiwania (BIP39)","Enter your password":"Wprowadź hasło","Enter your spending password":"Wprowadź hasło w celu wypłaty","Error at Wallet Service":"Błąd na Wallet Service","Error creating wallet":"Błąd podczas tworzenia portfela","Expired":"Wygasł","Expires":"Wygasa","Export options":"Opcje eksportu","Export to file":"Eksportuj do pliku","Export Wallet":"Eksport portfela","Exporting via QR not supported for this wallet":"Dla tego portfela nie jest obsługiwany eksport przez QR","Extended Public Keys":"Rozszerzone klucze publiczne","Extracting Wallet Information...":"Wyodrębnianie danych z portfela...","Failed to export":"Nie udało się wyeksportować","Failed to verify backup. Please check your information":"Nie udało się zweryfikować kopii zapasowej. Proszę sprawdzić swoje dane","Family vacation funds":"Fundusz wczasów rodzinnych","Fee":"Prowizja","Fetching Payment Information":"Pobieranie informacji o płatności","File/Text":"Plik/Tekst","Finger Scan Failed":"Skanowanie odcisku nie powiodło się","Finish":"Zakończ","For audit purposes":"Do celów audytu","French":"francuski","From the destination device, go to Add wallet > Import wallet and scan this QR code":"Z urządzenia docelowego, przejdź do Dodaj portfel > Import portfela i Zeskanuj ten kod QR","Funds are locked by pending spend proposals":"Fundusze są zablokowane przez rozpatrywane wniosku wypłaty","Funds found":"Znaleziono środki","Funds received":"Otrzymano środki","Funds will be transferred to":"Środki będą przekazane do","Generate new address":"Generuj nowy adres","Generate QR Code":"Generowanie kodu QR","Generating .csv file...":"Generowanie pliku csv...","German":"niemiecki","Getting address for wallet {{selectedWalletName}} ...":"Otrzymywanie adresu dla portfela {{selectedWalletName}} ...","Global preferences":"Ogólne preferencje","Hardware wallet":"Portfel sprzętowy","Hardware Wallet":"Portfel sprzętowy","Hide advanced options":"Ukryj opcje zaawansowane","I affirm that I have read, understood, and agree with these terms.":"Potwierdzam, że przeczytałem, zrozumiałem i zgadza się z regulaminem.","I AGREE. GET STARTED":"ZGADZAM SIĘ. ZACZYNAMY","Import":"Importuj","Import backup":"Importuj kopię zapasową","Import wallet":"Importuj portfel","Importing Wallet...":"Importowanie portfela...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"W żadnym wypadku autorzy oprogramowania, pracownicy i oddziały Bitpay, posiadacze praw autorskich, czy BitPay, Inc. nie ponoszą odpowiedzialności za wszelkie roszczenia, odszkodowania lub inne zobowiązania, zarówno wynikające z umowy, czynu niedozwolonego lub z innego tytułu, związanego z oprogramowaniem.","In order to verify your wallet backup, please type your password:":"W celu weryfikacji kopii zapasowej portfela wpisz swoje hasło:","Incorrect address network":"Nieprawidłowy adres sieciowy","Incorrect code format":"Niepoprawny format kodu","Insufficient funds":"Nie ma wystarczającej ilości środków","Insufficient funds for fee":"Niewystarczające środki na prowizję","Invalid":"Nieprawidłowy","Invalid account number":"Nieprawidłowy numer konta","Invalid address":"Nieprawidłowy adres","Invalid derivation path":"Nieprawidłowa ścieżka derywacji","Invitation to share a Copay Wallet":"Zaproszenie do współdzielenia portfela Copay","Italian":"włoski","Japanese":"japoński","John":"Jan","Join":"Dołącz","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Dołącz do mojego portfela Copay. Kod zaproszenia: {{secret}} Wersję desktopową lub aplikację na telefon można pobrać z https://copay.io","Join shared wallet":"Dołącz do portfela","Joining Wallet...":"Dołączanie do portfela...","Key already associated with an existing wallet":"Klucz jest już powiązany z istniejącym portfelem","Label":"Etykieta","Language":"Język","Last Wallet Addresses":"Ostatnie adresy portfela","Learn more about Copay backups":"Dowiedz się więcej o kopiach zapasowych Copay","Loading...":"Ładowanie...","locked by pending payments":"zablokowane przez oczekujące wypłaty","Locktime in effect. Please wait to create a new spend proposal":"Skuteczna blokada. Proszę czekać, aby utworzyć nowy wniosek wypłaty","Locktime in effect. Please wait to remove this spend proposal":"Skuteczna blokada. Proszę czekać, aby usunąć wniosek wypłaty","Make a payment to":"Wypłać do","Matches:":"Dopasowania:","me":"ja","Me":"Ja","Memo":"Notatka","Merchant message":"Wiadomość handlowa","Message":"Wiadomość","Missing parameter":"Brak parametru","Missing private keys to sign":"Brak kluczy prywatnych do podpisania","Moved":"Przeniesiony","Multiple recipients":"Wielu odbiorców","My Bitcoin address":"Mój adres Bitcoin","My contacts":"Moje kontakty","My wallets":"Moje portfele","Need to do backup":"Musisz zrobić kopię zapasową","Network":"Sieć","Network connection error":"Błąd połączenia z siecią","New Payment Proposal":"Nowy wniosek wypłaty","New Random Recovery Phrase":"Nowa losowa fraza odzyskiwania","No hardware wallets supported on this device":"Portfele sprzętowe nie są obsługiwane przez to urządzenie","No transactions yet":"Brak transakcji","Normal":"Zwykła","Not authorized":"Brak autoryzacji","Not completed":"Nie ukończono","Not enough funds for fee":"Brak środków na opłacenie prowizji","Not valid":"Nieprawidłowy","Note":"Notatka","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Uwaga: łącznie kwota {{amountAboveMaxSizeStr}} została wyłączona. Został przekroczony maksymalny rozmiar dozwolony dla transakcji","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Uwaga: łącznie kwota {{amountBelowFeeStr}} została wyłączona. Fundusze te pochodzą z UTXOs mniejszych niż gwarantowana prowizja sieci.","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"Uwaga: Aby zaimportować portfel z oprogramowania innego niż Copay, przejdź do Dodaj Portfel > Utwórz Portfel, i podaj tam frazę odzyskiwania.","Official English Disclaimer":"Oficjalna rezygnacja w języku angielskim","OKAY":"W PORZĄDKU","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"Po skopiowaniu frazy odzyskiwania portfela, zaleca się usunięcie jej z urządzenia.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Wyświetlane są tylko główne (niezmienne) adresy. Adresy na tej liście nie zostały w tej chwili zweryfikowane lokalnie.","Open Settings app":"Otwórz ustawienia aplikacji","optional":"opcjonalnie","Paper Wallet Private Key":"Klucz prywatny portfela papierowego","Participants":"Uczestnicy","Passphrase":"Hasło","Password":"Hasło","Password required. Make sure to enter your password in advanced options":"Wymagane hasło. Upewnij się, aby wprowadzić hasło w opcjach zaawansowanych","Paste invitation here":"Wklej tutaj zaproszenie","Paste the backup plain text code":"Wklej tekst kodu kopii zapasowej","Paste your paper wallet private key here":"Wklej tutaj prywatny klucz portfela papierowego","Pasted from clipboard":"Wklejone ze schowka","Pay To":"Zapłać","Payment Accepted":"Wypłata zaakceptowana","Payment accepted, but not yet broadcasted":"Wypłata zaakceptowana, ale jeszcze nie nadana","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Wypłata zaakceptowana. Będzie nadana przez Glidera. W przypadku wystąpienia problemu, może być usunięta 6 godzin po utworzeniu.","Payment details":"Szczegóły wypłaty","Payment expires":"Płatność wygasa","Payment Proposal":"Wniosek wypłaty","Payment Proposal Created":"Wniosek wypłaty utworzony","Payment Proposal Rejected":"Wniosek wypłaty odrzucony","Payment Proposal Rejected by Copayer":"Wniosek wypłaty odrzucony przez współwłaściciela portfela","Payment Proposal Signed by Copayer":"Wniosek wypłaty zatwierdzony przez współwłaściciela portfela","Payment Proposals":"Wniosek wypłaty","Payment Protocol Invalid":"Protokół wypłaty nieprawidłowy","Payment Protocol not supported on Chrome App":"Protokół wypłaty nieobsługiwany przez Chrome","Payment Rejected":"Wypłata odrzucona","Payment request":"Wniosek o płatność","Payment Sent":"Płatność wysłana","Payment to":"Wypłata dla","Pending Confirmation":"Oczekiwanie na potwierdzenie","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Trwale usuń ten portfel. TEN KROK JEST NIEODWRACALNY","Personal Wallet":"Portfel osobisty","Please enter the recovery phrase":"Wpisz frazę odzyskiwania","Please enter the required fields":"Proszę wypełnić wymagane pola","Please enter the wallet recovery phrase":"Wpisz frazę odzyskiwania portfela","Please tap the words in order to confirm your backup phrase is correctly written.":"Proszę wybrać słowa w celu potwierdzenia poprawności frazy odzyskiwania.","Please upgrade Copay to perform this action":"Proszę uaktualnić Copay, by móc wykonać tę operację","Please wait to be redirected...":"Proszę czekać na przekierowanie...","Please, select your backup file":"Proszę wybrać plik kopii zapasowej","Polish":"polski","Preferences":"Ustawienia","Preparing backup...":"Przygotowywanie kopii zapasowej...","preparing...":"Przygotowywanie...","Press again to exit":"Naciśnij ponownie, aby wyjść","Priority":"Priorytetowa","Private key is encrypted, cannot sign":"Klucz prywatny jest zaszyfrowany, nie można podpisać","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Powiadomienia Copay są obecnie wyłączone. Włącz je w ustawieniach aplikacji.","QR Code":"Kod QR","QR-Scanner":"Skaner kodów QR","Receive":"Otrzymaj","Received":"Otrzymane","Recipients":"Odbiorcy","Recovery Phrase":"Fraza odzyskiwania","Recovery phrase deleted":"Fraza odzyskiwania usunięta","Recreate":"Przywróć","Recreating Wallet...":"Przywracanie portfela...","Reject":"Odrzuć","Release Information":"Informacje o wersji","Remove":"Usuń","Repeat password":"Powtórz hasło","Repeat the password":"Powtórz hasło","Repeat the spending password":"Powtórz hasło wypłat","Request a specific amount":"Prośba o konkretną kwotę","Request Spending Password":"Wymaganie Hasła Wypłat","Required":"Wymagania","Required number of signatures":"Wymagana liczba podpisów","Retrieving inputs information":"Pobieranie informacji o danych wejściowych","Russian":"rosyjski","Save":"Zapisz","Scan addresses for funds":"Skanuj adresy w celu znalezienia środków","Scan Fingerprint":"Skanuj linie papilarne","Scan Finished":"Skanowanie zakończone","Scan status finished with error":"Stan skanowania zakończony błędem","Scan Wallet Funds":"Skanuj środki portfela","Scan your fingerprint please":"Proszę zeskanować linie papilarne","Scanning Wallet funds...":"Skanowanie środków portfela...","Search transactions":"Szukaj transakcji","Search Transactions":"Szukaj transakcji","Security preferences":"Ustawienia zabezpieczeń","See it on the blockchain":"Zobacz w blockchainie","Select a backup file":"Wybierz plik kopii zapasowej","Select a wallet":"Wybierz portfel","Self-signed Certificate":"Certyfikat z podpisem własnym","Send":"Wyślij","Send addresses by email":"Wyślij adresy przez e-mail","Send bitcoin":"Wyślij bitcoiny","Send by email":"Wyślij przez e-mail","Send Max":"Wyślij wszystko","Sending":"Wysyłanie","Sending transaction":"Wysyłanie transakcji","Sent":"Wysłane","Server response could not be verified":"Odpowiedź serwera nie mogła zostać zweryfikowana","Session log":"Dziennik sesji","SET":"ZATWIERDŹ","Set default url":"Ustaw domyślny adres url","Set up a password":"Ustawianie hasła","Set up a spending password":"Wprowadź hasło w celu wypłaty","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Włączenie powiadomień e-mail może mieć wpływ na twoją prywatność, jeżeli usługodawca portfela będzie narażony na ataki cyberprzestępców. Informacje dostępne dla atakującego będą zawierać jedynie adres twojego portfela i saldo.","Settings":"Ustawienia","Share address":"Udostępnij adres","Share invitation":"Wyślij zaproszenie","Share this invitation with your copayers":"Wyślij zaproszenie współwłaścicielom portfela","Share this wallet address to receive payments":"Udostępnij ten adres portfela w celu otrzymania płatności","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Udostępnij ten adres w celu otrzymania płatności. Aby chronić twoją prywatność nowe adresy są generowane automatycznie po ich użyciu.","Shared Wallet":"Współdzielony portfel","Show advanced options":"Pokaż opcje zaawansowane","Signatures rejected by server":"Podpisy odrzucone przez serwer","Signing transaction":"Podpisywanie transakcji","Single Address Wallet":"Pojedynczy adres portfela","Spanish":"hiszpański","Specify Recovery Phrase...":"Określ Frazę Odzyskiwania...","Spend proposal is not accepted":"Wniosek wypłaty nie został przyjęty","Spend proposal not found":"Wniosek wypłaty nie został znaleziony","Spending Password needed":"Wymagane Hasło Wypłat","Spending Passwords do not match":"Podane hasła różnią się","Success":"Udało się","Super Economy":"Super Ekonomiczna","Sweep paper wallet":"Wyczyść papierowy portfel","Sweep Wallet":"Wyczyść portfel","Sweeping Wallet...":"Sczytywanie portfela...","Tap and hold to show":"Dotknij i przytrzymaj, aby pokazać","Tap to retry":"Ponów próbę","Terms of Use":"Warunki użytkowania","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Autorzy oprogramowania, pracownicy i asystenci Bitpay, posiadacze praw autorskich i BitPay Inc. nie mogą odzyskać kluczy prywatnych lub haseł w wypadku ich utraty i nie mogą zagwarantować potwierdzenia transakcji, ponieważ nie mają kontroli nad siecią Bitcoin.","The derivation path":"Ścieżka derywacji","The Ledger Chrome application is not installed":"Aplikacja Ledger Chrome nie jest zainstalowana","The password of the recovery phrase (if set)":"Hasło odzyskiwania frazy (jeśli ustawione)","The payment was created but could not be completed. Please try again from home screen":"Wypłata została utworzona, ale nie może być zakończona. Spróbuj ponownie na stronie głównej","The payment was removed by creator":"Wypłata została usunięta przez jej twórcę","The recovery phrase could require a password to be imported":"Fraza odzyskiwania może wymagać hasła do zaimportowania","The request could not be understood by the server":"Wniosek nie został zrozumiany przez serwer","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Oprogramowanie nie jest kontem, gdzie BitPay lub inne osoby trzecie mogą służyć jako pośrednicy finansowi lub opiekunowie twoich bitcoinów.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Oprogramowanie to jest darmowym, open source, obsługującym multipodpisy cyfrowym portfelem.","The spend proposal is not pending":"Wniosek płatności nie jest oczekujący","The wallet \"{{walletName}}\" was deleted":"Portfel \"{{walletName}}\" został usunięty","The Wallet Recovery Phrase could require a password to be imported":"Fraza odzyskiwania portfela może wymagać hasła do zaimportowania","The wallet service URL":"Adres URL usługi Portfel","There are no wallets to make this payment":"Brak portfela, aby dokonać tej wypłaty","There is a new version of Copay. Please update":"Jest dostępna nowa wersja Copay. Proszę zaktualizować","There is an error in the form":"Wystąpił błąd w postaci","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"Ta fraza odzyskiwania został utworzona przy użyciu hasła. Aby odzyskać ten portfel potrzebna jest fraza odzyskiwania i hasło.","This transaction has become invalid; possibly due to a double spend attempt.":"Ta transakcja jest nieprawidłowa. Może to być spowodowane próbą podwójnej płatności.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Ten portfel nie jest zarejestrowany na Bitcore Wallet Service (BWS). Możesz go odtworzyć z lokalnego nośnika.","Time":"Czas","To":"Do","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Aby przywrócić ten {{index.m}}-{{index.n}} wspólny portfel musisz","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"W najszerszym zakresie dozwolonym przez prawo, to oprogramowanie jest dostarczane w stanie, w jakim jest (\"jak widać\") bez jakiejkolwiek gwarancji, ani wyraźnej, ani domyślnej, w tym między innymi domyślnych gwarancji co do przydatności handlowej, przydatności do określonych zastosowań i nienaruszalności.","too long!":"za długo!","Total Locked Balance":"Łącznie zablokowane środki","Total number of copayers":"Liczba współwłaścicieli portfela","Touch ID Failed":"Odczyt Touch ID nie powiódł się","Transaction":"Transakcja","Transaction already broadcasted":"Transakcja została już wysłana","Transaction History":"Historia transakcji","Translation Credits":"Przetłumaczone przez","Translators":"Tłumacze","Try again":"Spróbuj ponownie","Type the Recovery Phrase (usually 12 words)":"Wpisz frazę odzyskiwania (zazwyczaj 12 słów)","Unconfirmed":"Niepotwierdzone","Unit":"Jednostka","Unsent transactions":"Niewysłane transakcje","Updating transaction history. Please stand by.":"Aktualizowanie historii transakcji. Proszę czekać.","Updating Wallet...":"Aktualizowanie portfela...","Use Unconfirmed Funds":"Użyj niepotwierdzonych środków","Validating recovery phrase...":"Sprawdzanie poprawności frazy odzyskiwania...","Validating wallet integrity...":"Sprawdzanie integralności portfela...","Version":"Wersja","View":"Widok","Waiting for copayers":"Oczekiwanie na współwłaścicieli portfela","Waiting for Ledger...":"Oczekiwanie na Ledger...","Waiting for Trezor...":"Oczekiwanie na Trezor...","Waiting...":"Oczekiwanie...","Wallet already exists":"Portfel już istnieje","Wallet already in Copay":"Portfel jest już w Copay","Wallet Configuration (m-n)":"Konfiguracja portfela (m-n)","Wallet Export":"Eksport portfela","Wallet Id":"Id Portfela","Wallet incomplete and broken":"Awaria: Portfel nie działa","Wallet Information":"Informacje o portfelu","Wallet Invitation":"Zaproszenie do portfela","Wallet Invitation is not valid!":"Zaproszenie do portfela jest nieważne!","Wallet is full":"Portfel jest pełny","Wallet is locked":"Portfel jest zablokowany","Wallet is not complete":"Portfel jest niekompletny","Wallet name":"Nazwa portfela","Wallet Name (at creation)":"Nazwa portfela (oryginalna)","Wallet needs backup":"Portfel wymaga kopii zapasowej","Wallet Network":"Sieć portfela","Wallet not found":"Nie znaleziono portfela","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"Portfel nie jest zarejestrowany w Wallet Service. Odtwórz go używając polecenia \"Utwórz portfel\" z wykorzystaniem frazy odzyskiwania w ustawieniach zaawansowanych","Wallet Preferences":"Preferencje Portfela","Wallet Recovery Phrase":"Fraza Odzyskiwania Portfela","Wallet Recovery Phrase is invalid":"Fraza odzyskiwania portfela nieprawidłowa","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"Fraza odzyskiwania portfela niedostępna. Nadal można go wyeksportować w: Zaawansowane > Eksport portfela.","Wallet service not found":"Nie znaleziono serwera","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"Ostrzeżenie: klucz derywacji nie działa na tym urządzeniu/portfel. Działania dla tego portfela nie można wykonać.","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"UWAGA: Jeśli plik eksportu nie zawiera klucza prywatnego, możliwe będzie jedynie sprawdzenie salda i historii transakcji, jak również wygenerowanie wniosków o płatność. Nie może być on jednak używany do sprawdzania poprawności (podpisywania) wniosków płatności, więc środki z wyeksportowanego pliku nie będą dostępne.","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"OSTRZEŻENIE: Hasła nie można odzyskać. Pamiętaj, aby je zapisać. Portfela nie można przywrócić bez hasła.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"UWAGA: Klucz prywatny nie jest dostępny. Ten eksport umożliwia sprawdzenie salda i historii transakcji, jak również wygenerowanie wniosków o płatność. Nie może być on jednak używany do sprawdzania poprawności (podpisywania) wniosków płatności, więc środki z wyeksportowanego pliku nie będą dostępne.","Warning: this transaction has unconfirmed inputs":"Ostrzeżenie: ta transakcja ma niepotwierdzone dane wejściowe","WARNING: UNTRUSTED CERTIFICATE":"OSTRZEŻENIE: CERTYFIKAT NIEZAUFANY","WARNING: Wallet not registered":"Ostrzeżenie: Portfel niezarejestrowany","Warning!":"Ostrzeżenie!","We reserve the right to modify this disclaimer from time to time.":"Zastrzegamy sobie prawo do wprowadzania zmian w niniejszych warunkach użytkowania.","WELCOME TO COPAY":"WITAMY W COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Dopóki oprogramowanie jest w fazie testów i nadal, dzięki informacjom od użytkowników i społeczności programistów, dokonywane są poprawki, nie możemy zagwarantować, że będzie ono wolne od błędów.","Write your wallet recovery phrase":"Wpisz swoją frazę odzyskiwania portfela","Wrong number of recovery words:":"Nieprawidłowa ilość słów frazy:","Wrong spending password":"Nieprawidłowe hasło wypłat","Yes":"Tak","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Użytkownik przyjmuje do wiadomości, że korzysta z tego oprogramowania na własną odpowiedzialność i zgodnie z obowiązującym prawem.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Użytkownik jest odpowiedzialny za przechowywanie swoich haseł, kluczy publicznych i prywatnych, numerów PIN i innych kodów, których używa do uzyskania dostępu do oprogramowania.","You assume any and all risks associated with the use of the software.":"Użytkownik bierze na siebie wszelkie ryzyko związane z korzystaniem z tego oprogramowania.","You backed up your wallet. You can now restore this wallet at any time.":"Wykonałeś kopię zapasową portfela. Teraz możesz go odtworzyć w każdej chwili.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Możesz bezpiecznie zainstalować swój portfel na innym urządzeniu i używać go z wieloma urządzeniami jednocześnie.","You do not have any wallet":"Nie masz żadnego portfela","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"Potrzebujesz frazę odzyskiwania, aby móc odtworzyć ten portfel. Zapisz ją i przechowuj w bezpiecznym miejscu.","Your nickname":"Twój nick","Your password":"Twoje hasło","Your spending password":"Twoje hasło wypłat","Your wallet has been imported correctly":"Twój portfel został zaimportowany poprawnie","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"Klucz portfela będzie zaszyfrowany. Hasło wypłat nie może być odzyskane. Pamiętaj, aby je zapisać","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Twoja fraza odzyskiwania i dostęp do serwera koordynowały tworzenie początkowego portfela. Musisz jeszcze {{index.m}} w celu dokonania płatności."}); - gettextCatalog.setStrings('pt', {"(possible double spend)":"(possible double spend)","(Trusted)":"(Trusted)","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} will be deducted for bitcoin networking fees","{{index.m}}-of-{{index.n}}":"{{index.m}}-of-{{index.n}}","{{item.m}}-of-{{item.n}}":"{{item.m}}-of-{{item.n}}","{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance":"{{len}} carteiras importadas. Recursos de digitalização em andamento. Espere para ver o saldo atualizado","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.","OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).":"OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).","OR the wallet seed of all copayers in the wallet":"OR the wallet seed of all copayers in the wallet","OR the wallet seeds of all copayers in the wallet":"OR the wallet seeds of all copayers in the wallet","A multisignature bitcoin wallet":"Uma carteira de bitcoin multi-assinada","About Copay":"Sobre a Copay","Accept":"Aceitar","Add a Seed Passphrase":"Add a Seed Passphrase","Add an optional passphrase to secure the seed":"Add an optional passphrase to secure the seed","Add wallet":"Adicionar carteira","Address":"Endereço","Address Type":"Address Type","Advanced":"Avançado","Advanced Send":"Advanced Send","Agree":"Concordar","Alias for {{index.walletName}}":"Alias for {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at","All transaction requests are irreversible.":"All transaction requests are irreversible.","Already have a wallet?":"Já tem uma carteira?","Alternative Currency":"Moeda Alternativa","Amount":"Valor","Amount below dust threshold":"Amount below dust threshold","Amount in":"Montante em","Applying changes":"Aplicar alterações","Are you sure you want to delete the backup words?":"Are you sure you want to delete the backup words?","Are you sure you want to delete this wallet?":"Tem certeza que deseja excluir esta carteira?","Available Balance":"Saldo Disponível","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Average confirmation time: {{fee.nbBlocks * 10}} minutes","Back":"Voltar","Backup":"Backup","Backup now":"Backup agora","Backup words deleted":"Backup words deleted","Bad wallet invitation":"Bad wallet invitation","Balance By Address":"Balance By Address","Before receiving funds, it is highly recommended you backup your wallet keys.":"Antes de receber fundos, é altamente recomendável que você faça backup de suas chaves de carteira.","Bitcoin address":"Endereço Bitcoin","Bitcoin Network Fee Policy":"Bitcoin Network Fee Policy","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.":"Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.","Bitcoin URI is NOT valid!":"Bitcoin URI não é válido!","Broadcast Payment":"Transmitir Pagamento","Broadcasting Payment":"Transmitindo Pagamento","Broadcasting transaction":"Transmitindo transação","Browser unsupported":"Navegador não suportado","Cancel":"Cancelar","CANCEL":"CANCELAR","Cannot join the same wallet more that once":"Cannot join the same wallet more that once","Certified by":"Certificado por","Changing wallet alias only affects the local wallet name.":"Alterando o apelido da carteira somente afeta o nome da carteira local.","Choose a backup file from your computer":"Escolha um arquivo de backup do seu computador","Choose a wallet to send funds":"Choose a wallet to send funds","Close":"Fechar","Color":"Cor","Commit hash":"Commit de hash","Confirm":"Confirm","Confirmations":"Confirmações","Connecting to {{create.hwWallet}} Wallet...":"Connecting to {{create.hwWallet}} Wallet...","Connecting to {{import.hwWallet}} Wallet...":"Connecting to {{import.hwWallet}} Wallet...","Connecting to {{join.hwWallet}} Wallet...":"Connecting to {{join.hwWallet}} Wallet...","Copayer already in this wallet":"Copayer already in this wallet","Copayer already voted on this spend proposal":"Copayer already voted on this spend proposal","Copayer data mismatch":"Copayer data mismatch","Copayers":"Copayers","Copied to clipboard":"Copied to clipboard","Copy this text as it is to a safe place (notepad or email)":"Copie este texto como está para um lugar seguro (bloco de notas ou e-mail)","Copy to clipboard":"Copiar para área de transferência","Could not accept payment":"Could not accept payment","Could not access Wallet Service: Not found":"Could not access Wallet Service: Not found","Could not broadcast payment":"Could not broadcast payment","Could not create address":"Could not create address","Could not create payment proposal":"Não foi possível criar proposta de pagamento","Could not create using the specified extended private key":"Não foi possível criar usando a chave privada estendida especificada","Could not create using the specified extended public key":"Could not create using the specified extended public key","Could not create: Invalid wallet seed":"Could not create: Invalid wallet seed","Could not decrypt":"Could not decrypt","Could not decrypt file, check your password":"Não foi possível descriptografar o arquivo, verifique sua senha","Could not delete payment proposal":"Could not delete payment proposal","Could not fetch payment information":"Não foi possível obter a informação do pagamento","Could not fetch transaction history":"Não foi possível obter o histórico de transação","Could not import":"Could not import","Could not import. Check input file and password":"Não foi possível importar. Verifique o arquivo de entrada e senha","Could not join wallet":"Could not join wallet","Could not recognize a valid Bitcoin QR Code":"Could not recognize a valid Bitcoin QR Code","Could not reject payment":"Could not reject payment","Could not send payment":"Não foi possível enviar o pagamento","Could not update Wallet":"Não é possível atualizar carteira","Create":"Criar","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Create {{requiredCopayers}}-of-{{totalCopayers}} wallet","Create new wallet":"Criando nova carteira","Create, join or import":"Criar, participar ou importar","Created by":"Criado por","Creating Profile...":"Criando Perfil…","Creating transaction":"Criando transação","Creating Wallet...":"Criando Carteira…","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB","Date":"Data","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.","Delete it and create a new one":"Apagar e criar um novo","Delete Payment Proposal":"Excluir Proposta de Pagamento","Delete wallet":"Excluir carteira","Delete Wallet":"Excluir Carteira","DELETE WORDS":"DELETE WORDS","Deleting payment":"Excluindo pagamento","Derivation Strategy":"Derivation Strategy","Details":"Detalhes","Disabled":"Desabilitado","Do not include private key":"Do not include private key","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.","Download":"Download","Download CSV file":"Download CSV file","Economy":"Economy","Email":"Email","Email for wallet notifications":"Email for wallet notifications","Email Notifications":"Notificações por E-mail","Encrypted export file saved":"Encrypted export file saved","Enter the seed words (BIP39)":"Enter the seed words (BIP39)","Enter your password":"Digite sua senha","Error at Wallet Service":"Error at Wallet Service","Error creating wallet":"Erro na criação da carteira","Error importing wallet:":"Erro importando carteira:","Expires":"Expira","Export":"Export","Export options":"Export options","Extended Public Keys":"Extended Public Keys","External Private Key:":"External Private Key:","Failed to export":"Failed to export","Failed to import wallets":"Falha ao importar carteiras","Family vacation funds":"Fundos de férias com a família","Fee":"Fee","Fee Policy":"Fee Policy","Fee policy for this transaction":"Fee policy for this transaction","Fetching Payment Information":"Buscando Informação de Pagamento","File/Text Backup":"File/Text Backup","French":"Francês","Funds are locked by pending spend proposals":"Funds are locked by pending spend proposals","Funds found":"Funds found","Funds received":"Fundos recebidos","Funds will be transfered to":"Funds will be transfered to","Generate new address":"Gerar novo endereço","Generate QR Code":"Generate QR Code","Generating .csv file...":"Generating .csv file...","German":"Alemão","GET STARTED":"COMEÇAR","Getting address for wallet {{selectedWalletName}} ...":"Getting address for wallet {{selectedWalletName}} ...","Global settings":"Configurações globais","Go back":"Go back","Greek":"Grego","Hardware wallet":"Hardware wallet","Hardware Wallet":"Hardware Wallet","Have a Backup from Copay v0.9?":"Tem um Backup do Copay v 0.9?","Hide advanced options":"Hide advanced options","Hide Wallet Seed":"Hide Wallet Seed","History":"História","Home":"Início","I affirm that I have read, understood, and agree with these terms.":"I affirm that I have read, understood, and agree with these terms.","Import":"Importar","Import backup":"Importar backup","Import from Ledger":"Import from Ledger","Import from the Cloud?":"Importar da nuvem?","Import from TREZOR":"Import from TREZOR","Import here":"Importar aqui","Import wallet":"Importar carteira","Importing wallet...":"Importando carteira…","Importing...":"Importando…","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.","Incorrect address network":"Incorrect address network","Insufficient funds":"Insufficient funds","Insufficient funds for fee":"Insufficient funds for fee","Invalid":"Invalid","Invalid address":"Invalid address","Invitation to share a Copay Wallet":"Invitation to share a Copay Wallet","Italian":"Italiano","Japanese":"Japonês","John":"John","Join":"Participar","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io","Join shared wallet":"Associando carteira compartilhada","Joining Wallet...":"Associando-se a Carteira…","Key already associated with an existing wallet":"Key already associated with an existing wallet","Language":"Idioma","Last Wallet Addresses":"Last Wallet Addresses","Learn more about Copay backups":"Learn more about Copay backups","Learn more about Wallet Migration":"Saiba mais sobre Migração de Carteira","Loading...":"Loading...","locked by pending payments":"bloqueado por pagamentos pendentes","Locktime in effect. Please wait to create a new spend proposal":"Locktime in effect. Please wait to create a new spend proposal","Locktime in effect. Please wait to remove this spend proposal":"Locktime in effect. Please wait to remove this spend proposal","Make a payment to":"Fazer um pagamento para","me":"me","Me":"Eu","Memo":"Nota","Merchant message":"Mensagem do Comerciante","Message":"Mensagem","More":"Mais","Moved":"Movido","Multisignature wallet":"Carteira multi-assinada","My Bitcoin address":"Meu endereço Bitcoin","Network":"Rede","Network connection error":"Network connection error","New Payment Proposal":"Nova Proposta de Pagamento","No Private key":"No Private key","No transactions yet":"Nenhuma transação ainda","Normal":"Normal","Not authorized":"Not authorized","Not valid":"Inválido","Note":"Nota","Official English Disclaimer":"Official English Disclaimer","Once you have copied your wallet seed down, it is recommended to delete it from this device.":"Once you have copied your wallet seed down, it is recommended to delete it from this device.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.","optional":"opcional","Paper Wallet Private Key":"Paper Wallet Private Key","Participants":"Participantes","Passphrase":"Passphrase","Passphrase (if you have one)":"Passphrase (if you have one)","Password":"Senha","Password needed":"Senha necessária","Passwords do not match":"As senhas não coincidem","Paste invitation here":"Cole o convite aqui","Paste the backup plain text code":"Cole o texto puro do backup aqui","Paste your paper wallet private key here":"Paste your paper wallet private key here","Pay To":"Pagar Para","Payment Accepted":"Pagamento Aceito","Payment accepted, but not yet broadcasted":"Payment accepted, but not yet broadcasted","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.","Payment details":"Detalhes do pagamento","Payment Proposal":"Proposta de Pagamento","Payment Proposal Created":"Proposta de Pagamento Criada","Payment Proposal Rejected":"Proposta de Pagamento Rejeitada","Payment Proposal Rejected by Copayer":"Proposta de Pagamento Rejeitada pelo Copayer","Payment Proposal Signed by Copayer":"Proposta de Pagamento Assinada pelo Copayer","Payment Proposals":"Propostas de Pagamento","Payment Protocol Invalid":"Payment Protocol Invalid","Payment Protocol not supported on Chrome App":"Protocolo de pagamento não suportado no Chrome App","Payment rejected":"Payment rejected","Payment Rejected":"Pagamento Rejeitado","Payment request":"Pedido de pagamento","Payment sent":"Payment sent","Payment Sent":"Pagamento Enviado","Payment to":"Pagamento para","Pending Confirmation":"Pending Confirmation","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED","Personal Wallet":"Carteira Pessoal","Please enter the required fields":"Por favor, preencha os campos obrigatórios","Please enter the seed words":"Please enter the seed words","Please enter the wallet seed":"Please enter the wallet seed","Please upgrade Copay to perform this action":"Please upgrade Copay to perform this action","Please, select your backup file":"Por favor, selecione seu arquivo de backup","Portuguese":"Português","Preferences":"Preferências","Preparing backup...":"Preparing backup...","Priority":"Priority","QR Code":"QR Code","QR-Scanner":"QR-Scanner","Receive":"Receber","Received":"Recebido","Recipients":"Recipients","Reconnecting to Wallet Service...":"Reconectando ao Serviço de Carteira…","Recreate":"Recriado","Recreating Wallet...":"Recriando Carteira…","Reject":"Rejeitar","Rejecting payment":"Rejeitando pagamento","Release Information":"Liberar Informação","Repeat password":"Repetir Senha","Request a specific amount":"Request a specific amount","Request Password for Spending Funds":"Request Password for Spending Funds","Requesting Ledger Wallet to sign":"Requesting Ledger Wallet to sign","Required":"Obrigatório","Required number of signatures":"Required number of signatures","Retrying...":"Repetindo…","Russian":"Russian","Save":"Salvar","Saving preferences...":"Salvando preferências…","Scan addresses for funds":"Pesquisando endereços por fundos","Scan Finished":"Pesquisa Finalizada","Scan status finished with error":"Pesquisa de status finalizada com erro","Scan Wallet Funds":"Scan Wallet Funds","Scanning wallet funds...":"Scanning wallet funds...","Scanning Wallet funds...":"Pesquisando fundos de carteira…","See it on the blockchain":"Veja no blockchain","Seed passphrase":"Seed passphrase","Seed Passphrase":"Seed Passphrase","Select a backup file":"Selecione um arquivo de backup","Select a wallet":"Selecione uma carteira","Self-signed Certificate":"Self-signed Certificate","Send":"Enviar","Send All":"Send All","Send all by email":"Send all by email","Send by email":"Enviar por E-mail","Sending funds...":"Sending funds...","Sent":"Enviado","Server":"Servidor","Server response could not be verified":"Server response could not be verified","Session log":"Log da sessão","SET":"DEFINIR","Set up a Export Password":"Set up a Export Password","Set up a password":"Configure uma senha","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Configurar notificações de e-mail pode enfraquecer sua privacidade se o prestador de serviços de carteira está comprometido. As informações disponíveis para um invasor podem incluir seus endereços carteira e seu saldo, nada mais.","settings":"configurações","Share address":"Compartilhar endereço","Share invitation":"Compartilhar convite","Share this invitation with your copayers":"Compartilhe este convite com seus copayers","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Compartilhe este endereço da carteira para receber pagamentos. Para proteger sua privacidade, novos endereços são gerados automaticamente cada vez que você usá-los.","Shared Wallet":"Compartilhar Carteira","Show advanced options":"Show advanced options","Show Wallet Seed":"Show Wallet Seed","Signatures rejected by server":"Signatures rejected by server","Signing payment":"Pagamento assinado","SKIP BACKUP":"PULAR BACKUP","Spanish":"Espanhol","Specify your wallet seed":"Specify your wallet seed","Spend proposal is not accepted":"Spend proposal is not accepted","Spend proposal not found":"Spend proposal not found","Still not done":"Still not done","Success":"Sucesso","Sweep paper wallet":"Sweep paper wallet","Sweep Wallet":"Sweep Wallet","Tap to retry":"Bata para repetir","Terms of Use":"Terms of Use","Testnet":"Testnet","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.","The Ledger Chrome application is not installed":"The Ledger Chrome application is not installed","The payment was created but could not be completed. Please try again from home screen":"O pagamento foi criado mas não pode ser completado. Por favor, tente novamente a partir da tela inicial.","The payment was created but could not be signed. Please try again from home screen":"The payment was created but could not be signed. Please try again from home screen","The payment was removed by creator":"O pagamento foi removido pelo criador","The payment was signed but could not be broadcasted. Please try again from home screen":"The payment was signed but could not be broadcasted. Please try again from home screen","The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.":"The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.","The seed could require a passphrase to be imported":"The seed could require a passphrase to be imported","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"The software you are about to use functions as a free, open source, and multi-signature digital wallet.","The spend proposal is not pending":"The spend proposal is not pending","The wallet \"{{walletName}}\" was deleted":"A carteira “{{walletName}}” foi removida","There are no wallets to make this payment":"There are no wallets to make this payment","There is an error in the form":"Existe um erro no formulário","This transaction has become invalid; possibly due to a double spend attempt.":"This transaction has become invalid; possibly due to a double spend attempt.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Esta carteira não está registrada no dado serviço Wallet Service Bitcore (BWS) informado. Você pode recriá-la a partir da informação local.","Time":"Hora","To":"Para","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"To restore this {{index.m}}-{{index.n}} shared wallet you will need","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.","too long!":"muito tempo!","Total":"Total","Total Locked Balance":"Saldo Total Bloqueado","Total number of copayers":"Total number of copayers","Transaction":"Transação","Transaction already broadcasted":"Transaction already broadcasted","Translation Credits":"Translation Credits","Translators":"Translators","Type the Seed Word (usually 12 words)":"Type the Seed Word (usually 12 words)","Unable to send transaction proposal":"Impossível enviar a proposta de transação","Unconfirmed":"Não confirmado","Unit":"Unidade","Unsent transactions":"Transações não enviadas","Updating Wallet...":"Atualizando Carteira…","Use Ledger hardware wallet":"Use Ledger hardware wallet","Use TREZOR hardware wallet":"Use TREZOR hardware wallet","Use Unconfirmed Funds":"Use Unconfirmed Funds","Username":"Username","Version":"Versão","View":"View","Waiting for copayers":"Aguardando copayers","Waiting...":"Aguardando…","Wallet":"Wallet","Wallet Alias":"Apelido da Carteira","Wallet already exists":"A carteira já existe","Wallet Already Imported:":"Carteira já importada:","Wallet already in Copay:":"Wallet already in Copay:","Wallet Configuration (m-n)":"Wallet Configuration (m-n)","Wallet Export":"Wallet Export","Wallet Id":"Wallet Id","Wallet incomplete and broken":"Carteira incompleta e quebrada","Wallet Information":"Wallet Information","Wallet Invitation":"Convite para Carteira","Wallet Invitation is not valid!":"O convite para carteira não é válido!","Wallet is full":"Wallet is full","Wallet is not complete":"Wallet is not complete","Wallet name":"Nome da carteira","Wallet Name (at creation)":"Wallet Name (at creation)","Wallet Network":"Wallet Network","Wallet not found":"Wallet not found","Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed":"Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed","Wallet Seed":"Wallet Seed","Wallet Seed could require a passphrase to be imported":"Wallet Seed could require a passphrase to be imported","Wallet seed is invalid":"Wallet seed is invalid","Wallet seed not available. You can still export it from Advanced > Export.":"Wallet seed not available. You can still export it from Advanced > Export.","Wallet service not found":"Wallet service not found","WARNING: Backup needed":"Atenção: Backup necessário","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.":"WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.":"WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.","Warning: this transaction has unconfirmed inputs":"Warning: this transaction has unconfirmed inputs","WARNING: UNTRUSTED CERTIFICATE":"WARNING: UNTRUSTED CERTIFICATE","WARNING: Wallet not registered":"Atenção: Carteira não registrada","Warning!":"Atenção!","We reserve the right to modify this disclaimer from time to time.":"We reserve the right to modify this disclaimer from time to time.","WELCOME TO COPAY":"BEM-VINDO A COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.","Write it down and keep them somewhere safe.":"Write it down and keep them somewhere safe.","Wrong number of seed words:":"Wrong number of seed words:","Wrong password":"Senha errada","Yes":"Sim","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.","You assume any and all risks associated with the use of the software.":"You assume any and all risks associated with the use of the software.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"You can safely install your wallet on another device and use it from multiple devices at the same time.","You do not have a wallet":"Você não tem uma carteira","You need the wallet seed to restore this personal wallet.":"You need the wallet seed to restore this personal wallet.","Your backup password":"Sua senha de backup","Your export password":"Your export password","Your nickname":"Seu apelido","Your password":"Sua senha","Your profile password":"Sua senha de perfil","Your wallet has been imported correctly":"Sua carteira foi importada corretamente","Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down":"Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down","Your Wallet Seed":"Your Wallet Seed","Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend."}); - gettextCatalog.setStrings('ru', {"(possible double spend)":"(возможна двойная трата)","(Trusted)":"(Доверенный)","[Balance Hidden]":"[Баланс скрыт]","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} будет использовано для оплаты комиссии","{{feeRateStr}} of the transaction":"{{feeRateStr}} транзакции","{{index.m}}-of-{{index.n}}":"{{index.m}}-из-{{index.n}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} больше","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} транзакций скачено","{{item.m}}-of-{{item.n}}":"{{item.m}}-из-{{item.n}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Предложенный платёж может быть удалён если 1) вы создали этот платёж и никто его еще не подписал, или если 2) прошло более 24 часов с момента его создания.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"ЕСЛИ ВЫ ПОТЕРЯЕТЕ ДОСТУП К ВАШЕМУ КОШЕЛЬКУ COPAY ИЛИ ВАШИМ ЗАШИФРОВАННЫМ ЗАКРЫТЫМ КЛЮЧАМ, ПРИ ТОМ ЧТО У ВАС НЕТ ОТДЕЛЬНОЙ РЕЗЕРВНОЙ КОПИИ ВАШЕГО КОШЕЛЬКА И СООТВЕТСТВУЮЩЕМУ ЕМУ ПАРОЛЯ, ВЫ ПРИЗНАЁТЕ И СОГЛАШАЕТЕСЬ С ТЕМ ЧТО ВСЕ БИТКОЙНЫ АССОЦИИРОВАННЫЕ С ЭТИМ КОШЕЛЬКОМ СТАНУТ НЕДОСТУПНЫ.","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":"ИЛИ один экспортный файл и кворум остальных ключевых словосочетаний (например в кошельке 3-5: экспортный файл и два ключевых словосочетания двух любых совладельцев).","OR the wallet recovery phrase of all copayers in the wallet":"ИЛИ ключевое словосочетание всех совладельцев кошелька","OR the wallet recovery phrases of all copayers in the wallet":"ИЛИ ключевые словосочетания всех совладельцев кошелька","A multisignature bitcoin wallet":"Биткойн-кошелёк с мультиподписью","About Copay":"О Copay","Accept":"Принять","Account":"Аккаунт","Account Number":"Номер аккаунта","Activity":"Активность","Add a new entry":"Добавить новую запись","Add a Password":"Защитить паролем","Add an optional password to secure the recovery phrase":"Добавьте необязательный пароль для защиты ключевого словосочетания","Add comment":"Добавить комментарий","Add wallet":"Добавить кошелёк","Address":"Адрес","Address Type":"Тип адреса","Advanced":"Дополнительные возможности","Alias":"Псевдоним","Alias for {{index.walletName}}":"Псевдоним для {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Любой вклад в перевод Copay приветствуются. Регистрируйтесь на crowdin.com и присоединяйтесь к проекту Copay на","All transaction requests are irreversible.":"Все транзакции являются необратимыми.","Alternative Currency":"Альтернативная валюта","Amount":"Сумма","Amount below minimum allowed":"Сумма ниже допустимого минимума","Amount in":"Сумма в","Are you sure you want to delete the recovery phrase?":"Вы уверены, что хотите удалить ключевое словосочетание?","Are you sure you want to delete this wallet?":"Вы точно хотите удалить этот кошелек?","Auditable":"Проверяемый","Available Balance":"Доступный баланс","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Среднее время подтверждения: {{fee.nbBlocks * 10}} минут","Back":"Назад","Backup":"Резервное копирование","Backup failed":"Сбой резервного копирования","Backup Needed":"Требуется резервное копирование","Backup now":"Создать резервную копию","Bad wallet invitation":"Недействительное приглашение","Balance By Address":"Баланс на адресах","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"Прежде чем получать переводы вы должны создать резервную копию кошелька. Если это устройство будет утеряно, вы не сможете получить доступ к вашим средствам без резервной копии.","BETA: Android Key Derivation Test:":"БЕТА: Тест деривации ключей Android:","BIP32 path for address derivation":"Укажите BIP32 для генерации адресов","Bitcoin address":"Биткойн-адрес","Bitcoin Network Fee Policy":"Политика комиссии в сети Биткойн","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"Биткойн-транзакции могут включать комиссию, собираемую майнерами в сети. Чем выше комиссия, тем больше стимул для майнера включить транзакцию в блок. Текущая комиссия определяется на основе сетевой нагрузки и выбранной политики.","Bitcoin URI is NOT valid!":"Биткойн URI недействителен!","Broadcast Payment":"Отправить платёж","Broadcasting transaction":"Отправка транзакции","Browser unsupported":"Браузер не поддерживается","Calculating fee":"Вычисление комиссии","Cancel":"Отмена","Cancel and delete the wallet":"Отменить и удалить кошелёк","Cannot create transaction. Insufficient funds":"Не удается создать транзакцию. Недостаточно средств","Cannot join the same wallet more that once":"Нельзя присоединиться к одному и тому же кошельку более одного раза","Cannot sign: The payment request has expired":"Не удалось подписать: запрос платежа истёк","Certified by":"Сертифицирован","Changing wallet alias only affects the local wallet name.":"Изменение псевдонима кошелька сохраняется только локально.","Chinese":"Китайский","Choose a backup file from your computer":"Выберите файл резервной копии","Clear cache":"Очистить кэш","Close":"Закрыть","Color":"Цвет","Comment":"Комментарий","Commit hash":"Хэш версии","Confirm":"Подтвердить","Confirm your wallet recovery phrase":"Подтвердите ваше ключевое словосочетание","Confirmations":"Подтверждения","Congratulations!":"Поздравляем!","Connecting to Coinbase...":"Подключение к Coinbase...","Connecting to Glidera...":"Подключение к Glidera...","Connection reset by peer":"Соединение сброшено другой стороной","Continue":"Продолжить","Copayer already in this wallet":"Совладелец кошелька уже присоединился","Copayer already voted on this spend proposal":"Совладелец кошелька уже проголосовал по этому предложению платежа","Copayer data mismatch":"Несоответствие данных совладельца кошелька","Copayers":"Совладельцы кошелька","Copied to clipboard":"Скопировано в буфер обмена","Copy this text as it is to a safe place (notepad or email)":"Скопируйте этот текст как есть (в блокнот или письмо)","Copy to clipboard":"Скопировать в буфер обмена","Could not access the wallet at the server. Please check:":"Не удалось получить доступ к кошельку на сервере. Пожалуйста, проверьте:","Could not access wallet":"Не удалось получить доступ к кошельку","Could not access Wallet Service: Not found":"Не удалось получить доступ к серверу Bitcore: не найден","Could not broadcast payment":"Не удалось отправить платёж","Could not build transaction":"Не удалось создать транзакцию","Could not create address":"Не удалось создать адрес","Could not create payment proposal":"Не удалось создать предложение платежа","Could not create using the specified extended private key":"Не удалось создать используя указанный расширенный закрытый ключ","Could not create using the specified extended public key":"Не удалось создать используя указанный расширенный открытый ключ","Could not create: Invalid wallet recovery phrase":"Не удалось создать: недействительное ключевое словосочетание","Could not decrypt file, check your password":"Не удалось расшифровать файл, проверьте пароль","Could not delete payment proposal":"Не удалось удалить предложение платежа","Could not fetch payment information":"Не удалось получить информацию о платеже","Could not get fee value":"Не удалось получить информацию о комиссии","Could not import":"Не удалось импортировать","Could not import. Check input file and spending password":"Не удалось импортировать. Проверьте импортируемый файл и платёжный пароль","Could not join wallet":"Не удалось присоединиться к кошельку","Could not recognize a valid Bitcoin QR Code":"Не удалось распознать адрес в QR-коде","Could not reject payment":"Не удалось отклонить платёж","Could not send payment":"Не удалось отправить платёж","Could not update Wallet":"Не удалось обновить кошелёк","Create":"Создать","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Создать кошелёк {{requiredCopayers}}-из-{{totalCopayers}}","Create new wallet":"Создать новый кошелёк","Create, join or import":"Создать, присоединиться или импортировать","Created by":"Создан","Creating transaction":"Создание транзакции","Creating Wallet...":"Создание кошелька...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Текущая комиссия для этой политики: {{fee.feePerKBUnit}}/kiB","Czech":"Чешский","Date":"Дата","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Расшифровка бумажного кошелька может занять до пяти минут на этом устройстве. Пожалуйста, будьте терпеливы и держите приложение открытым.","Delete it and create a new one":"Удалите и создайте заново","Delete Payment Proposal":"Удалить предложенный платёж","Delete recovery phrase":"Удалить ключевое словосочетание","Delete Recovery Phrase":"Удалить ключевое словосочетание","Delete wallet":"Удалить кошелёк","Delete Wallet":"Удалить кошелёк","Deleting Wallet...":"Удаление кошелька...","Derivation Path":"Путь деривации","Derivation Strategy":"Стратегия деривации","Description":"Описание","Details":"Подробности","Disabled":"Отключены","Do not include private key":"Не включать закрытый ключ","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Не видите свой язык на Crowdin? Свяжитесь с владельцем по Crowdin! Мы с удовольствием поддержим ваш язык.","Done":"Завершено","Download":"Скачать","Economy":"Экономичная","Edit":"Редактировать","Edit comment":"Отредактировать комментарий","Edited by":"Отредактировано","Email for wallet notifications":"Укажите email для получения уведомлений","Email Notifications":"Email-уведомления","Empty addresses limit reached. New addresses cannot be generated.":"Достигнут предел пустых адресов. Новые адреса больше не могут быть сгенерированы.","Enable Coinbase Service":"Включить поддержку Coinbase","Enable Glidera Service":"Включить поддержку Glidera","Enable push notifications":"Включить Push-уведомления","Encrypted export file saved":"Зашифрованная резервная копия сохранена","Enter the recovery phrase (BIP39)":"Введите ключевое словосочетание (BIP39)","Enter your password":"Введите пароль","Enter your spending password":"Введите платёжный пароль","Error at Wallet Service":"Ошибка на сервере Bitcore","Error creating wallet":"Ошибка создания кошелька","Expired":"Истекла","Expires":"Срок действия","Export options":"Параметры экспорта","Export to file":"Экспорт в файл","Export Wallet":"Экспорт кошелька","Exporting via QR not supported for this wallet":"Экспорт QR-кодом не поддерживается для этого кошелька","Extended Public Keys":"Расширенные открытые ключи","Extracting Wallet Information...":"Извлечение информации о кошельке...","Failed to export":"Не удалось экспортировать","Failed to verify backup. Please check your information":"Не удалось проверить резервную копию. Пожалуйста, сверьте введённую мнемонику","Family vacation funds":"Отпускной бюджет","Fee":"Комиссия","Fetching Payment Information":"Извлечение информации о платеже","File/Text":"Файл/текст","Finger Scan Failed":"Не удалось сканировать отпечаток пальца","Finish":"Готово","For audit purposes":"Для целей ревизии","French":"французский","From the destination device, go to Add wallet > Import wallet and scan this QR code":"На целевом устройстве выберите \"Добавить кошелёк\" > \"Импорт кошелька\" и отсканируйте этот QR-код","Funds are locked by pending spend proposals":"Средства заблокированы ожидающим предложением платежа","Funds found":"Средства найдены","Funds received":"Получен перевод","Funds will be transferred to":"Средства будут переведены на","Generate new address":"Создать новый адрес","Generate QR Code":"Сгенерировать QR-код","Generating .csv file...":"Создание .сsv-файла...","German":"немецкий","Getting address for wallet {{selectedWalletName}} ...":"Получение адреса для кошелька {{selectedWalletName}}...","Global preferences":"Глобальные параметры","Hardware wallet":"Аппаратный кошелёк","Hardware Wallet":"Аппаратный кошелёк","Hide advanced options":"Скрыть дополнительные настройки","I affirm that I have read, understood, and agree with these terms.":"Я подтверждаю, что я прочитал(а), понял(а) и согласен(а) с настоящими условиями.","I AGREE. GET STARTED":"Принять и продолжить","Import":"Импорт","Import backup":"Импорт резервной копии","Import wallet":"Импорт кошелька","Importing Wallet...":"Импортирование кошелька...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"Ни при каких обстоятельствах авторы программного обеспечения, сотрудники и филиалов Bitpay, правообладатели, или BitPay Inc. не могут быть ответственным за любые претензии, убытки или нести иную ответственность, будь то действие контракта, деликта или иным образом вытекающие из или в связи с программным обеспечением.","In order to verify your wallet backup, please type your password:":"Для проверки резервной копии кошелька необходимо указать пароль:","Incorrect address network":"Неверный адрес","Incorrect code format":"Некорректный формат QR-кода","Insufficient funds":"Недостаточно средств","Insufficient funds for fee":"Недостаточно средств на комиссию","Invalid":"Недействительно","Invalid account number":"Недопустимый номер аккаунта","Invalid address":"Неверный адрес","Invalid derivation path":"Недействительный путь деривации","Invitation to share a Copay Wallet":"Приглашение присоединиться к кошельку Copay","Italian":"Итальянский","Japanese":"японский","John":"John","Join":"Присоединиться","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Присоединяйся к моему кошельку Copay. Код приглашения: {{secret}} Ты можешь загрузить Copay для своего телефона или настольного компьютера на сайте https://copay.io","Join shared wallet":"Присоединиться к общему кошельку","Joining Wallet...":"Присоединение к кошельку...","Key already associated with an existing wallet":"Ключ уже связан с существующим кошельком","Label":"Метка","Language":"Язык","Last Wallet Addresses":"Последние адреса","Learn more about Copay backups":"Узнайте больше о резервном копировании","Loading...":"Загрузка...","locked by pending payments":"заблокировано неподтверждёнными платежами","Locktime in effect. Please wait to create a new spend proposal":"Действует блокировка. Пожалуйста, подождите, чтобы создать новое предложение платежа","Locktime in effect. Please wait to remove this spend proposal":"Действует блокировка. Пожалуйста, подождите, чтобы удалить это предложение платежа","Make a payment to":"Сделать платёж","Matches:":"Совпадения:","me":"мне","Me":"Я","Memo":"Памятка","Merchant message":"Сообщение от продавца","Message":"Сообщение","Missing parameter":"Недостающий параметр","Missing private keys to sign":"Отсутствуют закрытые ключи для подписи","Moved":"Перемещено","Multiple recipients":"Несколько получателей","My Bitcoin address":"Мой биткойн-адрес","My contacts":"Мои контакты","My wallets":"Мои кошельки","Need to do backup":"Необходимо создать резервную копию","Network":"Сеть","Network connection error":"Ошибка подключения","New Payment Proposal":"Новое предложение платежа","New Random Recovery Phrase":"Сгенерированное случайным образом ключевое словосочетание","No hardware wallets supported on this device":"Аппаратные кошельки не поддерживаются на этом устройстве","No transactions yet":"Транзакций пока не было","Normal":"Обычная","Not authorized":"Не авторизован","Not completed":"Не завершено","Not enough funds for fee":"Недостаточно средств для уплаты комиссии","Not valid":"Недействительно","Note":"Примечание","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"Примечание: в общей сложности {{amountAboveMaxSizeStr}} были исключены. Превышен максимальный размер транзакции","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"Примечание: в общей сложности {{amountBelowFeeStr}} были исключены. Эти средства входят в UTXOs меньших, чем комиссия сети.","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"Примечание: для импортирования кошелька из другой программы откройте \"Добавить кошелек\" > \"Создать новый кошелек\", и укажите там ключевое словосочетание.","Official English Disclaimer":"Официальный оригинал","OKAY":"ХОРОШО","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"Рекомендуется удалить ключевое словосочетание с устройства, как только вы скопировали его.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Отображаются только основные адреса (не со сдачей). Адреса в этом списке на данный момент ещё не были проверены локально.","Open Settings app":"Открыть Параметры","optional":"необязательно","Paper Wallet Private Key":"Закрытый ключ бумажного кошелька","Participants":"Участники","Passphrase":"Пароль импортируемого кошелька","Password":"Пароль","Password required. Make sure to enter your password in advanced options":"Необходим пароль. Убедитесь, что вы ввели ваш пароль в дополнительных настройках","Paste invitation here":"Вставьте приглашение сюда","Paste the backup plain text code":"Вставьте код резервной копии обычным текстом","Paste your paper wallet private key here":"Вставьте закрытый ключ бумажного кошелька сюда","Pasted from clipboard":"Вставлено из буфера обмена","Pay To":"Отправить платёж","Payment Accepted":"Платёж принят","Payment accepted, but not yet broadcasted":"Платёж принят, но пока не отправлен","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Платёж принят и будет отправлен Glidera. В случае проблем он может быть удалён спустя шесть часов после создания.","Payment details":"Детали платежа","Payment expires":"Платёж истекает","Payment Proposal":"Предложение платежа","Payment Proposal Created":"Создано предложение платежа","Payment Proposal Rejected":"Предложение платежа отклонено","Payment Proposal Rejected by Copayer":"Предложение платежа отклонено совладельцем кошелька","Payment Proposal Signed by Copayer":"Предложение платежа подписано совладельцем кошелька","Payment Proposals":"Предложение платежа","Payment Protocol Invalid":"Недействительный протокол оплаты","Payment Protocol not supported on Chrome App":"Платёжный протокол не поддерживается в приложении Chrome","Payment Rejected":"Платёж отклонён","Payment request":"Запрос платежа","Payment Sent":"Платёж отправлен","Payment to":"Платёж","Pending Confirmation":"Ожидание подтверждения","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Окончательно удалить этот кошелёк. ЭТО ДЕЙСТВИЕ НЕ МОЖЕТ БЫТЬ ОТМЕНЕНО","Personal Wallet":"Личный кошелёк","Please enter the recovery phrase":"Введите ключевое словосочетание","Please enter the required fields":"Пожалуйста, заполните необходимые поля","Please enter the wallet recovery phrase":"Введите ключевое словосочетание кошелька","Please tap the words in order to confirm your backup phrase is correctly written.":"Коснитесь слов чтобы подтвердить, что ваша резервная копия корректно записана.","Please upgrade Copay to perform this action":"Пожалуйста, обновите Copay для выполнения этого действия","Please wait to be redirected...":"Дождитесь перенаправления...","Please, select your backup file":"Пожалуйста, выберите ваш файл резервной копии","Polish":"Польский","Preferences":"Параметры","Preparing backup...":"Подготовка резервной копии...","preparing...":"Подготавливается...","Press again to exit":"Нажмите еще раз для выхода","Priority":"Приоритетная","Private key is encrypted, cannot sign":"Закрытый ключ зашифрован, не удалось подписать","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Push-уведомления для Copay в настоящее время отключены. Включите их в Параметрах.","QR Code":"QR-код","QR-Scanner":"QR-сканер","Receive":"Получить","Received":"Получен","Recipients":"Получатели","Recovery Phrase":"Ключевое словосочетание","Recovery phrase deleted":"Ключевое словосочетание удалено","Recreate":"Создать заново","Recreating Wallet...":"Воссоздаю кошелёк...","Reject":"Отклонить","Release Information":"Информация о выпуске","Remove":"Удалить","Repeat password":"Повторите пароль","Repeat the password":"Повторите пароль","Repeat the spending password":"Повторно введите платёжный пароль","Request a specific amount":"Запросить определенную сумму","Request Spending Password":"Запрашивать платёжный пароль","Required":"Необходимо","Required number of signatures":"Требуемое число подписей","Retrieving inputs information":"Получение информации о входах","Russian":"русский","Save":"Сохранить","Scan addresses for funds":"Просканировать адреса для обнаружения средств","Scan Fingerprint":"Сканирование отпечатка пальца","Scan Finished":"Сканирование завершено","Scan status finished with error":"Сканирование завершено с ошибкой","Scan Wallet Funds":"Сканирование кошелька","Scan your fingerprint please":"Пожалуйста отсканируйте ваш отпечаток пальца","Scanning Wallet funds...":"Сканирование адресов кошелька...","Search transactions":"Поиск транзакций","Search Transactions":"Поиск транзакций","Security preferences":"Настройки безопасности","See it on the blockchain":"Посмотреть в блокчейне","Select a backup file":"Выберите файл резервной копии","Select a wallet":"Выберите кошелёк","Self-signed Certificate":"Самозаверенные сертификат","Send":"Отправить","Send addresses by email":"Отправить адреса по email","Send bitcoin":"Отправить","Send by email":"Отправить на email","Send Max":"Отправить максимум","Sending":"Отправка","Sending transaction":"Отправка транзакции","Sent":"Отправлено","Server response could not be verified":"Ответ сервера не может быть проверен","Session log":"Журнал сеанса","SET":"УСТАНОВИТЬ","Set default url":"Установить адресом по-умолчанию","Set up a password":"Задайте пароль","Set up a spending password":"Установить платёжный пароль","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Включение email-уведомлений может ослабить вашу конфиденциальность, если владелец сервера Bitcore будет скомпрометирован. Информация доступная злоумышленнику будет включать адреса вашего кошелька и его баланс, но ничего больше.","Settings":"Параметры","Share address":"Отправить адрес","Share invitation":"Отправить приглашение","Share this invitation with your copayers":"Отправьте приглашение совладельцам кошелька","Share this wallet address to receive payments":"Используйте этот адрес кошелька для получения платежей","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Используйте этот адрес для получения платежей. Для защиты вашей конфиденциальности, новые адреса создаются как только вы использовали старые.","Shared Wallet":"Общий кошелёк","Show advanced options":"Показать дополнительные настройки","Signatures rejected by server":"Подписи отклонены сервером","Signing transaction":"Подписание транзакции","Single Address Wallet":"Кошелек с одним адресом","Spanish":"испанский","Specify Recovery Phrase...":"Указать ключевое словосочетание...","Spend proposal is not accepted":"Предложение платежа не принято","Spend proposal not found":"Предложение платежа не найдено","Spending Password needed":"Необходим платёжный пароль","Spending Passwords do not match":"Платёжные пароли не совпадают","Success":"Успешно","Super Economy":"Очень экономичная","Sweep paper wallet":"Пополнить с бумажного кошелька","Sweep Wallet":"Считать кошелёк","Sweeping Wallet...":"Считывание кошелька...","Tap and hold to show":"Коснитесь и удерживайте, чтобы показать","Tap to retry":"Повторить","Terms of Use":"Условия использования","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"Авторы данного программного обеспечения, сотрудники и помощники Bitpay, владельцы авторских прав и BitPay Inc. не могут восстановить закрытые ключи или пароли если вы потеряете или забудете их, и не могут гарантировать подтверждение транзакции, так как они не имеют контроля над сетью Биткойн.","The derivation path":"Путь деривации","The Ledger Chrome application is not installed":"Приложение Ledger для Chrome не установлено","The password of the recovery phrase (if set)":"Пароль ключевого словосочетания (если установлен)","The payment was created but could not be completed. Please try again from home screen":"Платёж был создан, но не может быть завершен. Пожалуйста, попробуйте снова с главной страницы","The payment was removed by creator":"Платёж был удалён его создателем","The recovery phrase could require a password to be imported":"Для импортирования ключевого словосочетания может потребовать пароль","The request could not be understood by the server":"Запрос не распознан сервером","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"Программное обеспечение не представляет собой счет, обслуживаемый BitPay или иными третьим лицами в качестве финансовых посредников или хранителями ваших биткойнов.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"Программное обеспечение, которое вы начнёте сейчас использовать, функционирует как свободное, открытое программное обеспечение, и цифровой кошелёк с мультиподписью.","The spend proposal is not pending":"Предложение платежа не в ожидании","The wallet \"{{walletName}}\" was deleted":"Кошелёк «{{walletName}}» был удален","The Wallet Recovery Phrase could require a password to be imported":"Для импортирования ключевого словосочетания кошелька может потребовать пароль","The wallet service URL":"Адрес сервера Bitcore","There are no wallets to make this payment":"Нет кошельков, чтобы осуществить этот платёж","There is a new version of Copay. Please update":"Вышла новая версия Copay. Пожалуйста, обновитесь","There is an error in the form":"Ошибка в форме","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"Это ключевое словосочетание было создано с паролем. Для восстановления кошелька необходимо ключевое словосочетание и его пароль.","This transaction has become invalid; possibly due to a double spend attempt.":"Эта транзакция стала недействительной; возможно из-за попытки двойной траты.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Это кошелёк не зарегистрирован на данном сервере Bitcore. Вы можете воссоздать его из локальной информации.","Time":"Время","To":"Кому","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"Для восстановления этого {{index.m}}-{{index.n}} общего кошелька вам понадобится","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"В максимальной степени, разрешенной законом, данное программное обеспечение предоставляется “как есть” и без каких-либо явных, или подразумеваемых, заверений или гарантий, включая, но не ограничиваясь, товарную гарантию, пригодность для конкретной цели и ненарушения прав на интеллектуальную собственность.","too long!":"слишком долго!","Total Locked Balance":"Всего заблокировано средств","Total number of copayers":"Количество совладельцев","Touch ID Failed":"Ошибка Touch ID","Transaction":"Транзакция","Transaction already broadcasted":"Транзакция уже отправлена","Transaction History":"История транзакций","Translation Credits":"Благодарность за перевод","Translators":"Переводчики","Try again":"Попрoбуйте снова","Type the Recovery Phrase (usually 12 words)":"Введите ключевое словосочетание (обычно двенадцать слов)","Unconfirmed":"Неподтверждено","Unit":"Единица измерения","Unsent transactions":"Неотправленные транзакции","Updating transaction history. Please stand by.":"Обновление истории транзакций. Пожалуйста подождите.","Updating Wallet...":"Обновление кошелька...","Use Unconfirmed Funds":"Использовать неподтверждённые средства","Validating recovery phrase...":"Проверка ключевого словосочетания...","Validating wallet integrity...":"Проверка целостности кошелька...","Version":"Версия","View":"Просмотреть","Waiting for copayers":"Ожидание совладельцев кошелька","Waiting for Ledger...":"Ожидание Ledger...","Waiting for Trezor...":"Ожидание Trezor...","Waiting...":"Ожидание...","Wallet already exists":"Кошелёк уже существует","Wallet already in Copay":"Кошелёк уже в Copay","Wallet Configuration (m-n)":"Конфигурация кошелька (m-n)","Wallet Export":"Экспорт кошелька","Wallet Id":"Идентификатор кошелька","Wallet incomplete and broken":"Сбой: кошелёк не работает","Wallet Information":"Информация о кошельке","Wallet Invitation":"Приглашение присоединиться к кошельку","Wallet Invitation is not valid!":"Приглашение присоединиться к кошельку недействительно!","Wallet is full":"Все уже присоединены","Wallet is locked":"Кошелёк заблокирован","Wallet is not complete":"Не все ещё присоединились","Wallet name":"Название кошелька","Wallet Name (at creation)":"Название кошелька (при создании)","Wallet needs backup":"Необходимо создать резервную копию","Wallet Network":"Сеть кошелька","Wallet not found":"Кошелёк не найден","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"Кошелёк не зарегистрирован на сервере Bitcore. Пересоздайте кошелёк воспользовавшись дополнительными настройками, чтобы указать ключевое словосочетание","Wallet Preferences":"Параметры кошелька","Wallet Recovery Phrase":"Ключевое словосочетание кошелька","Wallet Recovery Phrase is invalid":"Ключевое словосочетание кошелька недействительно","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"Ключевое словосочетание недоступно. Вы все ещё можете экспортировать его в настройках кошелька \"Дополнительные возможности > Экспорт кошелька\".","Wallet service not found":"Сервер Bitcore не найден","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"ВНИМАНИЕ: Деривация ключей не работает на этом устройстве/кошельке. Никакие действия не могут быть произведены с этим кошельком.","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"ВНИМАНИЕ: если экспортируемый файл не включает закрытый ключ, поэтому позволит только просматривать баланс, историю транзакций и предлагать платежи. Однако, его нельзя будет использовать для одобрения (подписания) предложенных платежей, поэтому средства не будет доступны из экспортируемого файла.","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"ВНИМАНИЕ: Пароль нельзя восстановить. Убедитесь, что вы его записали. Этот кошелёк нельзя будет восстановить без пароля.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"ВНИМАНИЕ: Закрытый ключ этого кошелька недоступен. Экспортируемый файл позволит только просматривать баланс, историю транзакций и предлагать платежи. Однако, его нельзя будет использовать для одобрения (подписания) предложенных платежей, поэтому средства не будет доступны из экспортируемого файла.","Warning: this transaction has unconfirmed inputs":"Предупреждение: эта транзакция имеет неподтвержденные входы","WARNING: UNTRUSTED CERTIFICATE":"ВНИМАНИЕ: НЕНАДЕЖНЫЙ СЕРТИФИКАТ","WARNING: Wallet not registered":"ВНИМАНИЕ: Кошелёк не зарегистрирован","Warning!":"Внимание!","We reserve the right to modify this disclaimer from time to time.":"Мы оставляем за собой право время от времени изменять данный отказ от ответственности.","WELCOME TO COPAY":"ДОБРО ПОЖАЛОВАТЬ В COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"Пока программное обеспечение находится на этапе тестирования и продолжает улучшаться благодаря обратной связи от пользователей и сообщества разработчиков, мы не можем гарантировать, что в программном обеспечении не будет никаких ошибок.","Write your wallet recovery phrase":"Запишите ваше ключевое словосочетание","Wrong number of recovery words:":"Неподходящее количество слов в ключевом словосочетании:","Wrong spending password":"Неверный платёжный пароль","Yes":"Да","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"Вы подтверждаете, что вы используете программное обеспечение по вашему собственному усмотрению и в соответствии с применяемыми законами.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"Вы ответственны за хранение ваших паролей, открытых и закрытых ключей, ПИНов и других кодов, которые вы используете для доступа к программному обеспечению.","You assume any and all risks associated with the use of the software.":"Вы берете на себя все риски связанные с использованием данного программного обеспечения.","You backed up your wallet. You can now restore this wallet at any time.":"Резервная копия создана. Теперь вы можете восстановить кошелёк в любое время.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Вы можете установить ваш кошелек на другое устройство и использовать его с нескольких устройств одновременно.","You do not have any wallet":"У вас нет кошельков","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"Для восстановления этого кошелька нужно ключевое словосочетание. Запишите его и надёжно спрячьте.","Your nickname":"Ваше имя","Your password":"Ваш пароль","Your spending password":"Ваш платёжный пароль","Your wallet has been imported correctly":"Ваш кошелёк был успешно импортирован","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"Ваш кошелёк будет зашифрован. Платёжный пароль невозможно восстановить. Убедитесь, что записали его.","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Ключевое словосочетание и доступ к серверу, координировавшему начальное создание кошелька. Вам всё ещё нужно {{index.m}} для совершения платежей."}); - gettextCatalog.setStrings('sq', {"(possible double spend)":"(possible double spend)","(Trusted)":"(Trusted)","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} will be deducted for bitcoin networking fees","{{index.m}}-of-{{index.n}}":"{{index.m}}-of-{{index.n}}","{{item.m}}-of-{{item.n}}":"{{item.m}}-of-{{item.n}}","{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance":"{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.","OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).":"OR 1 wallet export file and the remaining quorum of wallet seeds (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet seeds of any of the other copayers).","OR the wallet seed of all copayers in the wallet":"OR the wallet seed of all copayers in the wallet","OR the wallet seeds of all copayers in the wallet":"OR the wallet seeds of all copayers in the wallet","A multisignature bitcoin wallet":"A multisignature bitcoin wallet","About Copay":"Rreth Copay","Accept":"Prano","Add a Seed Passphrase":"Add a Seed Passphrase","Add an optional passphrase to secure the seed":"Add an optional passphrase to secure the seed","Add wallet":"Shto kuletë","Address":"Adresa","Address Type":"Address Type","Advanced":"Avancuar","Advanced Send":"Dërgim i avancuar","Agree":"Pranoj","Alias for {{index.walletName}}":"Nofka për {{index.walletName}}","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at","All transaction requests are irreversible.":"All transaction requests are irreversible.","Already have a wallet?":"Tashmë keni një kuletë?","Alternative Currency":"Monedhë alternative","Amount":"Shuma","Amount below dust threshold":"Amount below dust threshold","Amount in":"Shuma në","Applying changes":"Duke aplikuar ndryshimet","Are you sure you want to delete the backup words?":"Are you sure you want to delete the backup words?","Are you sure you want to delete this wallet?":"Jeni i sigurtë që doni të fshini këtë kuletë?","Available Balance":"Shuma në dispozicion","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Koha mesatare e konfirmimit: {{fee.nbBlocks * 10}} minuta","Back":"Prapa","Backup":"Kopje rezervë","Backup now":"Krijo kopjen rezervë tani","Backup words deleted":"Backup words deleted","Bad wallet invitation":"Bad wallet invitation","Balance By Address":"Balance By Address","Before receiving funds, it is highly recommended you backup your wallet keys.":"Before receiving funds, it is highly recommended you backup your wallet keys.","Bitcoin address":"Bitcoin adresa","Bitcoin Network Fee Policy":"Bitcoin Network Fee Policy","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.":"Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.","Bitcoin URI is NOT valid!":"Bitcoin URI NUK është valid!","Broadcast Payment":"Transmeto pagesën","Broadcasting Payment":"Duke transmetuar pagesën","Broadcasting transaction":"Duke transmetuar transaksionin","Browser unsupported":"Shfletues i pambështetur","Cancel":"Anulo","CANCEL":"ANULO","Cannot join the same wallet more that once":"Cannot join the same wallet more that once","Certified by":"Çertifikuar nga","Changing wallet alias only affects the local wallet name.":"Ndërrimi i nofkës së kuletës ndikon vetëm në emrin lokal të kuletës.","Choose a backup file from your computer":"Choose a backup file from your computer","Choose a wallet to send funds":"Choose a wallet to send funds","Close":"Close","Color":"Color","Commit hash":"Commit hash","Confirm":"Confirm","Confirmations":"Confirmations","Connecting to {{create.hwWallet}} Wallet...":"Connecting to {{create.hwWallet}} Wallet...","Connecting to {{import.hwWallet}} Wallet...":"Connecting to {{import.hwWallet}} Wallet...","Connecting to {{join.hwWallet}} Wallet...":"Connecting to {{join.hwWallet}} Wallet...","Copayer already in this wallet":"Copayer already in this wallet","Copayer already voted on this spend proposal":"Copayer already voted on this spend proposal","Copayer data mismatch":"Copayer data mismatch","Copayers":"Copayers","Copied to clipboard":"Copied to clipboard","Copy this text as it is to a safe place (notepad or email)":"Copy this text as it is to a safe place (notepad or email)","Copy to clipboard":"Copy to clipboard","Could not accept payment":"Could not accept payment","Could not access Wallet Service: Not found":"Could not access Wallet Service: Not found","Could not broadcast payment":"Could not broadcast payment","Could not create address":"Could not create address","Could not create payment proposal":"Could not create payment proposal","Could not create using the specified extended private key":"Could not create using the specified extended private key","Could not create using the specified extended public key":"Could not create using the specified extended public key","Could not create: Invalid wallet seed":"Could not create: Invalid wallet seed","Could not decrypt":"Could not decrypt","Could not decrypt file, check your password":"Could not decrypt file, check your password","Could not delete payment proposal":"Could not delete payment proposal","Could not fetch payment information":"Could not fetch payment information","Could not fetch transaction history":"Could not fetch transaction history","Could not import":"Could not import","Could not import. Check input file and password":"Could not import. Check input file and password","Could not join wallet":"Could not join wallet","Could not recognize a valid Bitcoin QR Code":"Could not recognize a valid Bitcoin QR Code","Could not reject payment":"Could not reject payment","Could not send payment":"Could not send payment","Could not update Wallet":"Could not update Wallet","Create":"Create","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"Create {{requiredCopayers}}-of-{{totalCopayers}} wallet","Create new wallet":"Create new wallet","Create, join or import":"Create, join or import","Created by":"Created by","Creating Profile...":"Creating Profile...","Creating transaction":"Creating transaction","Creating Wallet...":"Creating Wallet...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB","Date":"Date","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.","Delete it and create a new one":"Delete it and create a new one","Delete Payment Proposal":"Delete Payment Proposal","Delete wallet":"Delete wallet","Delete Wallet":"Delete Wallet","DELETE WORDS":"DELETE WORDS","Deleting payment":"Deleting payment","Derivation Strategy":"Derivation Strategy","Details":"Details","Disabled":"Disabled","Do not include private key":"Do not include private key","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.","Download":"Download","Download CSV file":"Download CSV file","Economy":"Economy","Email":"Email","Email for wallet notifications":"Email for wallet notifications","Email Notifications":"Email Notifications","Encrypted export file saved":"Encrypted export file saved","Enter the seed words (BIP39)":"Enter the seed words (BIP39)","Enter your password":"Enter your password","Error at Wallet Service":"Error at Wallet Service","Error creating wallet":"Error creating wallet","Error importing wallet:":"Error importing wallet:","Expires":"Expires","Export":"Export","Export options":"Export options","Extended Public Keys":"Extended Public Keys","External Private Key:":"External Private Key:","Failed to export":"Failed to export","Failed to import wallets":"Failed to import wallets","Family vacation funds":"Family vacation funds","Fee":"Fee","Fee Policy":"Fee Policy","Fee policy for this transaction":"Fee policy for this transaction","Fetching Payment Information":"Fetching Payment Information","File/Text Backup":"File/Text Backup","French":"French","Funds are locked by pending spend proposals":"Funds are locked by pending spend proposals","Funds found":"Funds found","Funds received":"Funds received","Funds will be transfered to":"Funds will be transfered to","Generate new address":"Generate new address","Generate QR Code":"Generate QR Code","Generating .csv file...":"Generating .csv file...","German":"German","GET STARTED":"GET STARTED","Getting address for wallet {{selectedWalletName}} ...":"Getting address for wallet {{selectedWalletName}} ...","Global settings":"Global settings","Go back":"Go back","Greek":"Greek","Hardware wallet":"Hardware wallet","Hardware Wallet":"Hardware Wallet","Have a Backup from Copay v0.9?":"Have a Backup from Copay v0.9?","Hide advanced options":"Hide advanced options","Hide Wallet Seed":"Hide Wallet Seed","History":"History","Home":"Home","I affirm that I have read, understood, and agree with these terms.":"I affirm that I have read, understood, and agree with these terms.","Import":"Import","Import backup":"Import backup","Import from Ledger":"Import from Ledger","Import from the Cloud?":"Import from the Cloud?","Import from TREZOR":"Import from TREZOR","Import here":"Import here","Import wallet":"Import wallet","Importing wallet...":"Importing wallet...","Importing...":"Importing...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.","Incorrect address network":"Incorrect address network","Insufficient funds":"Insufficient funds","Insufficient funds for fee":"Insufficient funds for fee","Invalid":"Invalid","Invalid address":"Invalid address","Invitation to share a Copay Wallet":"Invitation to share a Copay Wallet","Italian":"Italian","Japanese":"Japanese","John":"John","Join":"Join","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io","Join shared wallet":"Join shared wallet","Joining Wallet...":"Joining Wallet...","Key already associated with an existing wallet":"Key already associated with an existing wallet","Language":"Language","Last Wallet Addresses":"Last Wallet Addresses","Learn more about Copay backups":"Learn more about Copay backups","Learn more about Wallet Migration":"Learn more about Wallet Migration","Loading...":"Loading...","locked by pending payments":"locked by pending payments","Locktime in effect. Please wait to create a new spend proposal":"Locktime in effect. Please wait to create a new spend proposal","Locktime in effect. Please wait to remove this spend proposal":"Locktime in effect. Please wait to remove this spend proposal","Make a payment to":"Make a payment to","me":"me","Me":"Me","Memo":"Memo","Merchant message":"Merchant message","Message":"Message","More":"More","Moved":"Moved","Multisignature wallet":"Multisignature wallet","My Bitcoin address":"My Bitcoin address","Network":"Network","Network connection error":"Network connection error","New Payment Proposal":"New Payment Proposal","No Private key":"No Private key","No transactions yet":"No transactions yet","Normal":"Normal","Not authorized":"Not authorized","Not valid":"Not valid","Note":"Note","Official English Disclaimer":"Official English Disclaimer","Once you have copied your wallet seed down, it is recommended to delete it from this device.":"Once you have copied your wallet seed down, it is recommended to delete it from this device.","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.","optional":"optional","Paper Wallet Private Key":"Paper Wallet Private Key","Participants":"Participants","Passphrase":"Passphrase","Passphrase (if you have one)":"Passphrase (if you have one)","Password":"Password","Password needed":"Password needed","Passwords do not match":"Passwords do not match","Paste invitation here":"Paste invitation here","Paste the backup plain text code":"Paste the backup plain text code","Paste your paper wallet private key here":"Paste your paper wallet private key here","Pay To":"Pay To","Payment Accepted":"Payment Accepted","Payment accepted, but not yet broadcasted":"Payment accepted, but not yet broadcasted","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.","Payment details":"Payment details","Payment Proposal":"Payment Proposal","Payment Proposal Created":"Payment Proposal Created","Payment Proposal Rejected":"Payment Proposal Rejected","Payment Proposal Rejected by Copayer":"Payment Proposal Rejected by Copayer","Payment Proposal Signed by Copayer":"Payment Proposal Signed by Copayer","Payment Proposals":"Payment Proposals","Payment Protocol Invalid":"Payment Protocol Invalid","Payment Protocol not supported on Chrome App":"Payment Protocol not supported on Chrome App","Payment rejected":"Payment rejected","Payment Rejected":"Payment Rejected","Payment request":"Payment request","Payment sent":"Payment sent","Payment Sent":"Payment Sent","Payment to":"Payment to","Pending Confirmation":"Pending Confirmation","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED","Personal Wallet":"Personal Wallet","Please enter the required fields":"Please enter the required fields","Please enter the seed words":"Please enter the seed words","Please enter the wallet seed":"Please enter the wallet seed","Please upgrade Copay to perform this action":"Please upgrade Copay to perform this action","Please, select your backup file":"Please, select your backup file","Portuguese":"Portuguese","Preferences":"Preferences","Preparing backup...":"Preparing backup...","Priority":"Priority","QR Code":"QR Code","QR-Scanner":"QR-Scanner","Receive":"Receive","Received":"Received","Recipients":"Recipients","Reconnecting to Wallet Service...":"Reconnecting to Wallet Service...","Recreate":"Recreate","Recreating Wallet...":"Recreating Wallet...","Reject":"Reject","Rejecting payment":"Rejecting payment","Release Information":"Release Information","Repeat password":"Repeat password","Request a specific amount":"Request a specific amount","Request Password for Spending Funds":"Request Password for Spending Funds","Requesting Ledger Wallet to sign":"Requesting Ledger Wallet to sign","Required":"Required","Required number of signatures":"Required number of signatures","Retrying...":"Retrying...","Russian":"Russian","Save":"Save","Saving preferences...":"Saving preferences...","Scan addresses for funds":"Scan addresses for funds","Scan Finished":"Scan Finished","Scan status finished with error":"Scan status finished with error","Scan Wallet Funds":"Scan Wallet Funds","Scanning wallet funds...":"Scanning wallet funds...","Scanning Wallet funds...":"Scanning Wallet funds...","See it on the blockchain":"See it on the blockchain","Seed passphrase":"Seed passphrase","Seed Passphrase":"Seed Passphrase","Select a backup file":"Select a backup file","Select a wallet":"Select a wallet","Self-signed Certificate":"Self-signed Certificate","Send":"Send","Send All":"Send All","Send all by email":"Send all by email","Send by email":"Send by email","Sending funds...":"Sending funds...","Sent":"Sent","Server":"Server","Server response could not be verified":"Server response could not be verified","Session log":"Session log","SET":"SET","Set up a Export Password":"Set up a Export Password","Set up a password":"Set up a password","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.","settings":"settings","Share address":"Share address","Share invitation":"Share invitation","Share this invitation with your copayers":"Share this invitation with your copayers","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.","Shared Wallet":"Shared Wallet","Show advanced options":"Show advanced options","Show Wallet Seed":"Show Wallet Seed","Signatures rejected by server":"Signatures rejected by server","Signing payment":"Signing payment","SKIP BACKUP":"SKIP BACKUP","Spanish":"Spanish","Specify your wallet seed":"Specify your wallet seed","Spend proposal is not accepted":"Spend proposal is not accepted","Spend proposal not found":"Spend proposal not found","Still not done":"Still not done","Success":"Success","Sweep paper wallet":"Sweep paper wallet","Sweep Wallet":"Sweep Wallet","Tap to retry":"Tap to retry","Terms of Use":"Terms of Use","Testnet":"Testnet","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.","The Ledger Chrome application is not installed":"The Ledger Chrome application is not installed","The payment was created but could not be completed. Please try again from home screen":"The payment was created but could not be completed. Please try again from home screen","The payment was created but could not be signed. Please try again from home screen":"The payment was created but could not be signed. Please try again from home screen","The payment was removed by creator":"The payment was removed by creator","The payment was signed but could not be broadcasted. Please try again from home screen":"The payment was signed but could not be broadcasted. Please try again from home screen","The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.":"The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.","The seed could require a passphrase to be imported":"The seed could require a passphrase to be imported","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"The software you are about to use functions as a free, open source, and multi-signature digital wallet.","The spend proposal is not pending":"The spend proposal is not pending","The wallet \"{{walletName}}\" was deleted":"The wallet \"{{walletName}}\" was deleted","There are no wallets to make this payment":"There are no wallets to make this payment","There is an error in the form":"There is an error in the form","This transaction has become invalid; possibly due to a double spend attempt.":"This transaction has become invalid; possibly due to a double spend attempt.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.","Time":"Time","To":"To","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"To restore this {{index.m}}-{{index.n}} shared wallet you will need","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.","too long!":"too long!","Total":"Total","Total Locked Balance":"Total Locked Balance","Total number of copayers":"Total number of copayers","Transaction":"Transaction","Transaction already broadcasted":"Transaction already broadcasted","Translation Credits":"Translation Credits","Translators":"Translators","Type the Seed Word (usually 12 words)":"Type the Seed Word (usually 12 words)","Unable to send transaction proposal":"Unable to send transaction proposal","Unconfirmed":"Unconfirmed","Unit":"Unit","Unsent transactions":"Unsent transactions","Updating Wallet...":"Updating Wallet...","Use Ledger hardware wallet":"Use Ledger hardware wallet","Use TREZOR hardware wallet":"Use TREZOR hardware wallet","Use Unconfirmed Funds":"Use Unconfirmed Funds","Username":"Username","Version":"Version","View":"View","Waiting for copayers":"Waiting for copayers","Waiting...":"Waiting...","Wallet":"Wallet","Wallet Alias":"Wallet Alias","Wallet already exists":"Wallet already exists","Wallet Already Imported:":"Wallet Already Imported:","Wallet already in Copay:":"Wallet already in Copay:","Wallet Configuration (m-n)":"Wallet Configuration (m-n)","Wallet Export":"Wallet Export","Wallet Id":"Wallet Id","Wallet incomplete and broken":"Wallet incomplete and broken","Wallet Information":"Wallet Information","Wallet Invitation":"Wallet Invitation","Wallet Invitation is not valid!":"Wallet Invitation is not valid!","Wallet is full":"Wallet is full","Wallet is not complete":"Wallet is not complete","Wallet name":"Wallet name","Wallet Name (at creation)":"Wallet Name (at creation)","Wallet Network":"Wallet Network","Wallet not found":"Wallet not found","Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed":"Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed","Wallet Seed":"Wallet Seed","Wallet Seed could require a passphrase to be imported":"Wallet Seed could require a passphrase to be imported","Wallet seed is invalid":"Wallet seed is invalid","Wallet seed not available. You can still export it from Advanced > Export.":"Wallet seed not available. You can still export it from Advanced > Export.","Wallet service not found":"Wallet service not found","WARNING: Backup needed":"WARNING: Backup needed","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.":"WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.","WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.":"WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.","Warning: this transaction has unconfirmed inputs":"Warning: this transaction has unconfirmed inputs","WARNING: UNTRUSTED CERTIFICATE":"WARNING: UNTRUSTED CERTIFICATE","WARNING: Wallet not registered":"WARNING: Wallet not registered","Warning!":"Warning!","We reserve the right to modify this disclaimer from time to time.":"We reserve the right to modify this disclaimer from time to time.","WELCOME TO COPAY":"WELCOME TO COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.","Write it down and keep them somewhere safe.":"Write it down and keep them somewhere safe.","Wrong number of seed words:":"Wrong number of seed words:","Wrong password":"Wrong password","Yes":"Yes","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.","You assume any and all risks associated with the use of the software.":"You assume any and all risks associated with the use of the software.","You can safely install your wallet on another device and use it from multiple devices at the same time.":"You can safely install your wallet on another device and use it from multiple devices at the same time.","You do not have a wallet":"You do not have a wallet","You need the wallet seed to restore this personal wallet.":"You need the wallet seed to restore this personal wallet.","Your backup password":"Your backup password","Your export password":"Your export password","Your nickname":"Your nickname","Your password":"Your password","Your profile password":"Your profile password","Your wallet has been imported correctly":"Your wallet has been imported correctly","Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down":"Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down","Your Wallet Seed":"Your Wallet Seed","Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"Your wallet seed and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend."}); - gettextCatalog.setStrings('tr', {"(possible double spend)":"(olası çift harcama)","(Trusted)":"(Güvenilir)","{{fee}} will be deducted for bitcoin networking fees":"{{fee}} bitcoin ağ ücreti olarak düşülecektir","{{index.m}}-of-{{index.n}}":"{{index.m}} te {{index.n}}","{{item.m}}-of-{{item.n}}":"{{item.n}} te {{item.m}}","{{len}} wallets imported. Funds scanning in progress. Hold on to see updated balance":"{{len}} cüzdanı içe aktarıldı. Fonlar taranırken ve güncellenirken bekleyiniz","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* Ödeme isteği; 1) kaynağı sizseniz, başka bir kullanıcı tarafından imzalanmamışsa veya 2) üzerinden 24 saat geçmişse silinebilir.","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"COPAY CÜZDANINIZA ERİŞİMİNİZİ KAYBEDER VEYA GEREKLİ ŞİFRESİ İLE BİRLİKTE CÜZDANINIZI ÖZEL ANAHTARLA BİRLİKTE YEDEKLEMEZSENİZ, COPAY CÜZDANINIZDAKİ BİTCOİN'LERE ERİŞİMİNİZİN KALMAYACAĞINI KABUL EDER VE ONAYLIYORSUNUZ DEMEKTİR.","A multisignature bitcoin wallet":"Çoklu imzalı bitcoin cüzdanı","About Copay":"Copay Hakkında","Accept":"Onay","Add an optional passphrase to secure the seed":"Kurtarma sözcüklerinin güvenliği için opsiyonel parola ekle","Add wallet":"Cüzdan ekle","Address":"Adres","Address Type":"Adres Türü","Advanced":"Gelişmiş","Advanced Send":"Gelişmiş Gönderme","Agree":"Kabul","Alias for {{index.walletName}}":"{{index.walletName}} için takma ad","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"Copay'nın çevirisi için tüm katkılarınızı bekliyoruz. Crowdin.com sitesine kayıt olun ve Copay Projesi'ne katılın","All transaction requests are irreversible.":"Işlem isteklerinin hiç biri geri alınamaz.","Already have a wallet?":"Zaten bir cüzdanınız var mı?","Alternative Currency":"Alternatif Para Birimi","Amount":"Tutar","Amount below dust threshold":"Kabul edilenden düşük miktar","Amount in":"Tutar","Are you sure you want to delete the backup words?":"Yedekleme kelimelerini silmek istediğinizden emin misiniz?","Are you sure you want to delete this wallet?":"Bu cüzdanı silmek istediğinizden emin misiniz?","Available Balance":"Kullanılabilir Bakiye","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"Ortalama onay süresi: {{fee.nbBlocks * 10}} dakika","Back":"Geri","Backup":"Yedekleme","Backup now":"Şimdi yedekle","Backup words deleted":"Yedekleme kelimeleri silindi","Bad wallet invitation":"Geçersiz cüzdan daveti","Balance By Address":"Adrese göre Bakiye","Before receiving funds, it is highly recommended you backup your wallet keys.":"Para almadan önce cüzdanınızı mutlaka yedeklemeniz önerilir.","Bitcoin address":"Bitcoin adresi","Bitcoin Network Fee Policy":"Bitcoin ağ ücret politikası","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Actual fees are determined based on network load and the selected policy.":"Bitcoin işlemlerine ağda madenciler tarafından toplanan ücret dahildir. Daha yüksek ücret, madenciler için işleminizi bloklarına eklemek için daha teşvik edicidir. Gerçek ücretler ağ yüküne ve seçili ilkeye göre belirlenir.","Bitcoin URI is NOT valid!":"Bitcoin URI geçerli değil!","Broadcast Payment":"Ödemeyi Yayınla","Broadcasting Payment":"Ödeme Yayınlanıyor","Broadcasting transaction":"İşlem yayınlanıyor","Browser unsupported":"Desteklenmeyen tarayıcı","Cancel":"İptal","CANCEL":"İPTAL","Cannot join the same wallet more that once":"Aynı cüzdana birden fazla kez girilemez","Certified by":"Tarafından sertifikalı","Changing wallet alias only affects the local wallet name.":"Cüzdan takma adı değişikliği sadece yerel cüzdan adını etkiler.","Choose a backup file from your computer":"Bilgisayarınızdan bir yedek dosyası seçin","Close":"Kapat","Color":"Renk","Commit hash":"Commit hash","Confirm":"Onayla","Confirmations":"Onaylı","Copayer already in this wallet":"Copayer zaten bu cüzdan içinde","Copayer already voted on this spend proposal":"Copayer bu teklifi oylamış","Copayer data mismatch":"Copayer veri uyuşmazlığı","Copayers":"Copayers","Copied to clipboard":"Panoya kopyalandı","Copy this text as it is to a safe place (notepad or email)":"Bu metni güvenli bir yere kopyalayın (Not Defteri veya e-posta)","Copy to clipboard":"Panoya kopyala","Could not accept payment":"Ödeme kabul edilemedi","Could not access Wallet Service: Not found":"Cüzdan hizmetine erişilemedi: Bulunamadı","Could not broadcast payment":"Ödeme yayınlanamadı","Could not create address":"Adres oluşturulamadı","Could not create payment proposal":"Ödeme teklifi oluşturulamadı","Could not create using the specified extended private key":"Belirtilen genişletilmiş özel anahtar kullanılarak oluşturulamadı","Could not create using the specified extended public key":"Belirtilen genişletilmiş genel anahtar kullanılarak oluşturulamadı","Could not create: Invalid wallet seed":"Oluşturulamadı: geçersiz cüzdan kelimeleri","Could not decrypt file, check your password":"Dosyanın şifresi çözülemedi, parolanızı kontrol edin","Could not delete payment proposal":"Ödeme teklifi silinemedi","Could not fetch payment information":"Ödeme bilgileri alınamadı","Could not fetch transaction history":"İşlem geçmişi alınamadı","Could not import":"İçe alınamadı","Could not import. Check input file and password":"İçe alınamadı. Dosyayı ve parolanızı kontrol edin","Could not join wallet":"Cüzdana katılma başarısız","Could not recognize a valid Bitcoin QR Code":"Geçerli bir Bitcoin QR kodu tanımıyor","Could not reject payment":"Ödeme reddedilemedi","Could not send payment":"Ödeme gönderemedi","Could not update Wallet":"Cüzdan güncellenemedi","Create":"Oluştur","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"{{totalCopayers}} {{requiredCopayers}} için cüzdan oluştur","Create new wallet":"Yeni cüzdan oluştur","Create, join or import":"Oluştur, birleştir veya içe al","Created by":"Oluşturan Kişi","Creating Profile...":"Profil oluşturuluyor...","Creating transaction":"İşlem oluşturuluyor","Creating Wallet...":"Cüzdan oluşturuluyor...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"Bu ilke için geçerli ücret oranı: {{fee.feePerKBUnit}}/kiB","Date":"Tarih","Delete it and create a new one":"Sil ve yeni bir tane oluştur","Delete Payment Proposal":"Ödeme teklifini sil","Delete wallet":"Cüzdanı sil","Delete Wallet":"Cüzdanı Sil","DELETE WORDS":"KELİMELERİ SİL","Deleting payment":"Ödeme siliniyor","Derivation Strategy":"Türetme Stratejisi","Details":"Ayrıntılar","Disabled":"Devre Dışı","Do not include private key":"Özel anahtarı dahil etme","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"Kendi dilinizi görmüyor musunuz? Crowdin kurucusu ile irtibata geçin! Dilinizi desteklemekten mutluluk duyarız.","Download":"İndir","Download CSV file":"CSV dosyasını indir","Economy":"Ekonomik","Email":"E-posta","Email for wallet notifications":"E-posta ile cüzdan bildirimleri","Email Notifications":"E-posta Bildirimleri","Encrypted export file saved":"Dışa alınan şifrelenmiş dosya kaydedildi","Enter the seed words (BIP39)":"Kurtarma sözcüklerini girin (BIP39)","Enter your password":"Parolanızı girin","Error at Wallet Service":"Cüzdan hizmeti hatası","Error creating wallet":"Cüzdan oluşturma hatası","Error importing wallet:":"Cüzdan içe alma hatası:","Expires":"Sona Erme","Export options":"Dışa aktarma seçenekleri","Extended Public Keys":"Genişletilmiş Genel Anahtarlar","Failed to export":"Dışa aktarma başarısız oldu","Failed to import wallets":"Cüzdan içe alma başarısız oldu","Family vacation funds":"Aile tatil fonları","Fee":"Ücret","Fee Policy":"Ücret politikası","Fee policy for this transaction":"Bu işlem için ücret politikası","Fetching Payment Information":"Ödeme Bilgileri Alınıyor","File/Text Backup":"Dosya/Metin Yedekleme","French":"Fransızca","Funds are locked by pending spend proposals":"Fonlar bekleyen işlem teklifleri tarafından kilitlendi","Funds received":"Ödeme alındı","Generate new address":"Yeni adres oluştur","Generate QR Code":"QR kodu oluştur","Generating .csv file...":"Csv dosyası oluşturuluyor...","German":"Almanca","GET STARTED":"Başlarken","Getting address for wallet {{selectedWalletName}} ...":"{{selectedWalletName}} için cüzdan adresi alınıyor...","Global settings":"Genel ayarlar","Go back":"Geri dön","Greek":"Yunanca","Hardware wallet":"Donanım cüzdanı","Have a Backup from Copay v0.9?":"Copay v0.9 sürümünden bir yedeğiniz mi var?","Hide advanced options":"Gelişmiş seçenekleri gizle","Hide Wallet Seed":"Cüzdan Sözcüklerini Gizle","History":"Geçmiş","Home":"Ana sayfa","I affirm that I have read, understood, and agree with these terms.":"Bu koşulları okuduğumu, anladığımı ve kabul ettiğimi onaylıyorum.","Import":"İçe aktar","Import backup":"Yedeği içe aktar","Import from the Cloud?":"Yedeği buluttan mı aktaracaksınız?","Import here":"Buraya içe aktar","Import wallet":"Cüzdanı içe aktar","Importing wallet...":"Cüzdan içe aktarılıyor...","Importing...":"İçe aktarılıyor...","Incorrect address network":"Yanlış adres ağı","Insufficient funds":"Yetersiz bakiye","Insufficient funds for fee":"Ücret için yetersiz bakiye","Invalid":"Geçersiz","Invalid address":"Geçersiz adres","Invitation to share a Copay Wallet":"Copay cüzdanını paylaşmak için davet","Italian":"İtalyanca","Japanese":"Japonca","John":"John","Join":"Katıl","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"Copay cüzdanıma katılın. İşte davetiye kodu: {{secret}} Copay'i telefon veya masaüstü ortamlarına indirmek için https://copay.io","Join shared wallet":"Paylaşılan cüzdana katıl","Joining Wallet...":"Cüzdana katılınılıyor...","Language":"Dil","Last Wallet Addresses":"Son Cüzdan Adresleri","Learn more about Copay backups":"Copay yedeklemeleri hakkında daha fazla bilgi edinin","Learn more about Wallet Migration":"Cüzdan birleştirme hakkında daha fazla bilgi","Loading...":"Yükleneniyor...","locked by pending payments":"bekleyen ödemeler yüzünden kilitlendi","Locktime in effect. Please wait to create a new spend proposal":"Yeni bir harcama teklifi oluşturmak için lütfen biraz bekleyin","Locktime in effect. Please wait to remove this spend proposal":"Harcama teklifini kaldırmak için lütfen biraz bekleyin","Make a payment to":"Ödeme yapılacak kişi","me":"ben","Me":"Beni","Memo":"Kısa Not","Merchant message":"Tüccar mesajı","Message":"Mesajınız","Moved":"Taşındı","My Bitcoin address":"Bitcoin adresim","Network":"Ağ","Network connection error":"Ağ bağlantı hatası","New Payment Proposal":"Yeni ödeme teklifi","No transactions yet":"Henüz hiç bir işlem yok","Normal":"Normal","Not authorized":"Yetkili değil","Not valid":"Geçerli değil","Note":"Not","Official English Disclaimer":"Resmi İngilizce Yasal Uyarı","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"Yalnızca ana (değişmemiş) adresler gösteriliyor. Bu listedeki adresler yerel olarak şu anda doğrulanmadı.","optional":"isteğe bağlı","Participants":"Katılımcılar","Passphrase":"Parola","Password":"Parola","Password needed":"Parola gerekli","Passwords do not match":"Parolalar eşleşmiyor","Paste invitation here":"Daveti buraya yapıştır","Paste the backup plain text code":"Yedek düz metin kodu yapıştırın","Pay To":"Ödenecek Kişi","Payment Accepted":"Ödeme Kabul Edildi","Payment accepted, but not yet broadcasted":"Ödeme kabul edildi ama henüz yayınlanmadı","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"Ödeme kabul edildi ve Glidera tarafından yayınlanacak. Bir sorun oluşması durumunda, yaratıldıktan 6 saat sonra silinebilir.","Payment details":"Ödeme detayları","Payment Proposal":"Ödeme Teklifi","Payment Proposal Created":"Ödeme Teklifi Oluşturuldu","Payment Proposal Rejected":"Ödeme Teklifi Reddedildi","Payment Proposal Rejected by Copayer":"Ödeme teklifi bir Copayer tarafından reddedildi","Payment Proposal Signed by Copayer":"Ödeme teklifi bir Copayer tarafından kabul edildi","Payment Proposals":"Ödeme Teklifleri","Payment Protocol Invalid":"Ödeme Protokolü Geçersiz","Payment Protocol not supported on Chrome App":"Ödeme Protokolü Chrome uygulaması üzerinde desteklenmiyor","Payment rejected":"Ödeme reddedildi","Payment Rejected":"Ödeme Reddedildi","Payment request":"Ödeme talebi","Payment sent":"Ödeme gönderildi","Payment Sent":"Ödeme Gönderildi","Payment to":"Ödenecek","Pending Confirmation":"Onay Bekleniyor","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"Bu cüzdanı kalıcı olarak sil. BU EYLEM GERİ ALINAMAZ","Personal Wallet":"Kişisel Cüzdan","Please enter the required fields":"Lütfen gerekli alanları girin","Please enter the seed words":"Lütfen kurtarma sözcüklerini girin","Please enter the wallet seed":"Lütfen cüzdan sözcüklerini girin","Please upgrade Copay to perform this action":"Bu eylemi gerçekleştirmek için lütfen Copay sürümünü yükseltin","Please, select your backup file":"Lütfen yedek dosyanızı seçin","Portuguese":"Portekizce","Preferences":"Tercihler","Preparing backup...":"Yedekleme hazırlanıyor...","Priority":"Öncelikli","QR Code":"QR Kodu","QR-Scanner":"QR-Tarayıcı","Receive":"Alma","Received":"Alındı","Recipients":"Alıcılar","Reconnecting to Wallet Service...":"Cüzdan servisine bağlanıyor...","Recreate":"Yeniden oluştur","Recreating Wallet...":"Cüzdan yeniden oluşturuluyor...","Reject":"Reddet","Rejecting payment":"Ödeme reddediliyor","Release Information":"Sürüm Bilgileri","Repeat password":"Şifreyi tekrarla","Request a specific amount":"Belirli bir miktar iste","Requesting Ledger Wallet to sign":"Ana defter, imzalanmak için isteniyor","Required":"Zorunlu","Required number of signatures":"Gerekli imza sayısı","Retrying...":"Yeniden deneniyor...","Russian":"Rusça","Save":"Kaydet","Saving preferences...":"Tercihler kaydediliyor...","Scan addresses for funds":"Fonlar için adresleri tara","Scan Finished":"Tarama tamamlandı","Scan status finished with error":"Tarama işlemi hatalı bitti","Scanning Wallet funds...":"Cüzdan para miktarı taranıyor...","See it on the blockchain":"Blockchain üzerinde gör","Seed passphrase":"Kurtarma sözcükleri parolası","Seed Passphrase":"Kurtarma Sözcükleri Parolası","Select a backup file":"Yedek dosyasını seçin","Select a wallet":"Bir cüzdan seçin","Self-signed Certificate":"Kendinden imzalı Sertifika","Send":"Gönder","Send All":"Tümünü Gönder","Send by email":"E-posta ile gönder","Sent":"Gönderildi","Server":"Sunucu","Server response could not be verified":"Sunucu yanıtı doğrulanamadı","Session log":"Oturum günlüğü","SET":"AYARLA","Set up a Export Password":"Dışa Alım parolası ayarla","Set up a password":"Parola ayarla","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"E-posta bildirimleri ayarlamak gizliliğinizi zayıflatabilir. Cüzdan sağlayıcısı ele geçirilirse, bazı bilgiler saldırganların eline geçebilir ancak bu bilgiler sadece cüzdan adresiniz ve bakiyeniz olacaktır.","Share address":"Adresi paylaş","Share invitation":"Davet paylaş","Share this invitation with your copayers":"Bu daveti copayers ile paylaş","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"Ödemeler için bu cüzdan adresinizi paylaşın. Gizliliğinizi korumak için, her kullandığınızda yeni bir adres otomatik olarak üretilir.","Shared Wallet":"Paylaşımlı Cüzdan","Show advanced options":"Gelişmiş seçenekleri göster","Show Wallet Seed":"Cüzdan Kurtarma Sözcüklerini Göster","Signatures rejected by server":"İmzalar sunucu tarafından reddedildi","Signing payment":"Ödeme imzalanıyor","SKIP BACKUP":"YEDEKLEMEYİ GEÇ","Spanish":"İspanyolca","Spend proposal is not accepted":"Harcama teklifi kabul edilmedi","Spend proposal not found":"Harcama teklifi bulunamadı","Still not done":"Halen tamamlanmadı","Success":"Başarılı","Tap to retry":"Yeniden denemek için dokunun","Terms of Use":"Kullanım Şartları","Testnet":"TestNet","The Ledger Chrome application is not installed":"Ledger Chrome uygulaması kurulu değil","The payment was created but could not be completed. Please try again from home screen":"Ödeme oluşturuldu ancak tamamlanamadı. Lütfen ana ekrandan yeniden deneyin","The payment was created but could not be signed. Please try again from home screen":"Ödeme oluşturuldu ancak tamamlanamadı. Lütfen ana ekrandan yeniden deneyin","The payment was removed by creator":"Ödeme yaratıcısı tarafından kaldırıldı","The payment was signed but could not be broadcasted. Please try again from home screen":"Ödeme imzalandı ancak değil yayınlanmadı. Lütfen ana ekrandan yeniden deneyin","The private key for this wallet is encrypted. Exporting keep the private key encrypted in the export archive.":"Bu cüzdan için özel anahtar şifrelidir. Dışa alım durumunda yine şifreli kalacaktır.","The seed could require a passphrase to be imported":"Kurtarma sözcükleri içe alım için parola gerektirebilir","The spend proposal is not pending":"Harcama teklifi beklemede değil","The wallet \"{{walletName}}\" was deleted":"\"{{walletName}}\" cüzdanı silindi","There are no wallets to make this payment":"Bu ödemeyi yapmak için hiçbir cüzdan yok","There is an error in the form":"Formda bir hata oluştu","This transaction has become invalid; possibly due to a double spend attempt.":"Bu işlem muhtemel bir çift harcama girişimi yüzünden geçersiz hale geldi.","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"Bu cüzdan Bitcore cüzdan Servisi'ne (BWS) kayıtlı değil. Yerel bilgilerle yeniden oluşturabilirsiniz.","Time":"Zaman","To":"Alıcı","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"{{index.m}}-{{index.n}} kurtarma için paylaşılan bir cüzdana ihtiyacınız var","too long!":"çok uzun!","Total":"Toplam","Total Locked Balance":"Toplam Kilitli Bakiye","Total number of copayers":"Copayers toplam sayısı","Transaction":"İşlem","Transaction already broadcasted":"İşlem zaten yayınlanmış","Translation Credits":"Çeviride Emeği Geneçler","Translators":"Çevirmenler","Type the Seed Word (usually 12 words)":"Kurtarma Sözcüklerini Girin (genelde 12 sözcük)","Unable to send transaction proposal":"İşlem teklifi gönderilemedi","Unconfirmed":"Onaylanmamış","Unit":"Birim","Unsent transactions":"Gönderilmemiş işlemler","Updating Wallet...":"Cüzdan güncelleniyor...","Use Unconfirmed Funds":"Doğrulanmamış fonları kullan","Username":"Kullanıcı adı","Version":"Sürüm","Waiting for copayers":"Copayers bekleniyor","Waiting...":"Bekliyor...","Wallet":"Cüzdan","Wallet Alias":"Cüzdan takma adı","Wallet already exists":"Cüzdan zaten var","Wallet Already Imported:":"Cüzdan zaten içe alındı:","Wallet already in Copay:":"Copay'de kayıtlı olan cüzdan:","Wallet Configuration (m-n)":"Cüzdan Yapılandırma (m-n)","Wallet Id":"Cüzdan Id","Wallet incomplete and broken":"Cüzdan eksik ve arızalı","Wallet Information":"Cüzdan Bilgisi","Wallet Invitation":"Cüzdan daveti","Wallet Invitation is not valid!":"Cüzdan daveti geçerli değil!","Wallet is full":"Cüzdan dolu","Wallet is not complete":"Cüzdan tamamlanmadı","Wallet name":"Cüzdan ismi","Wallet Name (at creation)":"Cüzdan ismi (oluşturmadaki)","Wallet Network":"Cüzdan Ağı","Wallet not found":"Cüzdan bulunamadı","Wallet not registed at the Wallet Service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your seed":"Cüzdan kayıtlı değil. Kurtarma sözcükleri belirlemek için Cüzdan Servisinden kaydedebilirsiniz","Wallet Seed":"Cüzdan Kurtarma Sözcükleri","Wallet Seed could require a passphrase to be imported":"Cüzdan kurtarma sözcükleri içe alım için parola gerektirebilir","Wallet seed is invalid":"Cüzdan kurtarma sözcükleri geçersiz","Wallet seed not available. You can still export it from Advanced > Export.":"Cüzdan kurtarma sözcükleri kullanılabilir değil. Yine de Gelişmiş > Dışa Alım adımından dışa alabilirsiniz.","Wallet service not found":"Cüzdan hizmeti bulunamadı","WARNING: Backup needed":"Uyarı: Yedekleme gereklidir","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"Özel anahtar olmadan cüzdanınızdaki miktarı ve işlem geçmişini görebilir, ödeme isteği oluşturabilirsiniz ancak herhangi bir ödeme gönderemezsiniz (sign) yani cüzdandaki paraya ulaşılamaz olarak kalır.","WARNING: Passphrase cannot be recovered. Be sure to write it down. The wallet can not be restored without the passphrase.":"UYARI: Parola kurtarma seçeneği yoktur. Bir yere yazdığınızdan emin olun. Cüzdanınız parola olmadan kurtarılamaz.","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"UYARI: Bu cüzdan için için özel anahtar kullanılabilir değil. Özel anahtar olmadan cüzdanınızdaki miktarı ve işlem geçmişini görebilir, ödeme isteği oluşturabilirsiniz ancak herhangi bir ödeme gönderemezsiniz (sign) yani cüzdandaki paraya ulaşılamaz olarak kalır.","WARNING: This seed was created with a passphrase. To recover this wallet both the mnemonic and passphrase are needed.":"Kurtarma sözcükleri bir parola ile desteklendi. Bu cüzdanı kurtarmak için, kurtarma sözcüklerine ve parolaya ihtiyaç olacaktır.","Warning: this transaction has unconfirmed inputs":"Uyarı: Bu işlem doğrulanmamış girişler içeriyor","WARNING: UNTRUSTED CERTIFICATE":"UYARI: GÜVENİLİR OLMAYAN SERTİFİKA","WARNING: Wallet not registered":"UYARI: Cüzdan kayıtlı değil","Warning!":"Uyarı!","We reserve the right to modify this disclaimer from time to time.":"Zaman zaman bu reddi değiştirme hakkımızı saklı tutarız.","WELCOME TO COPAY":"COPAY'E HOŞGELDİNİZ","Write it down and keep them somewhere safe.":"Not edin ve güvenli bir yerde saklayın.","Wrong number of seed words:":"Kurtarma sözcükleri sayısı yanlış:","Wrong password":"Hatalı şifre","Yes":"Evet","You can safely install your wallet on another device and use it from multiple devices at the same time.":"Cüzdanınızı başka bir cihaza güvenle kurabilir ve aynı anda birden çok platformda kullanabilirsiniz.","You do not have a wallet":"Cüzdanınız yok","You need the wallet seed to restore this personal wallet.":"Bu cüzdanı yüklemek için kurtarma sözcüklerine ihtiyacınız var.","Your backup password":"Yedekleme parolanız","Your export password":"Dışa alım parolanız","Your nickname":"Takma adınız","Your password":"Parolanız","Your profile password":"Profil parolanız","Your wallet has been imported correctly":"Cüzdan başarıyla içe aktarıldı","Your wallet key will be encrypted. Password cannot be recovered. Be sure to write it down":"Cüzdan anahtarınız şifrelenecek ve parolanız için bir kurtarma seçeneği olmayacak. Parolanızı bir yere yazdığınızdan emin olun","Your Wallet Seed":"Cüzdan Kurtama Sözcükleriniz"}); - gettextCatalog.setStrings('zh', {"(possible double spend)":"(重复支付)","(Trusted)":"(可信的)","[Balance Hidden]":"[隐藏余额]","{{fee}} will be deducted for bitcoin networking fees":"扣除比特币网络费 {{fee}}","{{feeRateStr}} of the transaction":"交易的{{feeRateStr}}","{{index.m}}-of-{{index.n}}":"{{index.n}} 分之 {{index.m}}","{{index.result.length - index.txHistorySearchResults.length}} more":"{{index.result.length - index.txHistorySearchResults.length}} 更多","{{index.txProgress}} transactions downloaded":"{{index.txProgress}} 条交易已下载","{{item.m}}-of-{{item.n}}":"{{item.n}} 分之 {{item.m}}","* A payment proposal can be deleted if 1) you are the creator, and no other copayer has signed, or 2) 24 hours have passed since the proposal was created.":"* 如果 1) 你是创造者,及没有其他 copayer 签名,或 2) 24 小时已经过去,支付提议将被删除。","IF YOU LOSE ACCESS TO YOUR COPAY WALLET OR YOUR ENCRYPTED PRIVATE KEYS AND YOU HAVE NOT SEPARATELY STORED A BACKUP OF YOUR WALLET AND CORRESPONDING PASSWORD, YOU ACKNOWLEDGE AND AGREE THAT ANY BITCOIN YOU HAVE ASSOCIATED WITH THAT COPAY WALLET WILL BECOME INACCESSIBLE.":"如果你无法访问你的 COPAY 钱包或加密私钥,及你没有分开储存钱包备份和相应密码,你承认并同意有关 COPAY 钱包里的任何比特币将不可被存取。","OR 1 wallet export file and the remaining quorum of wallet recovery phrases (e.g. in a 3-5 wallet: 1 wallet export file + 2 wallet recovery phrases of any of the other copayers).":" 1 钱包导出文件和钱包恢复短语的剩余法定人数 (例如在 3-5 钱包︰1 钱包导出文件 + 任何其他 copayers 的 2 钱包恢复短语)。","OR the wallet recovery phrase of all copayers in the wallet":" 钱包里的 所有 copayers 的钱包恢复短语","OR the wallet recovery phrases of all copayers in the wallet":" 钱包里的 所有 copayers 的钱包恢复短语","A multisignature bitcoin wallet":"多重签名比特币钱包","About Copay":"Copay 简介","Accept":"同意","Account":"帐户","Account Number":"帐号","Activity":"活动","Add a new entry":"添加新条目","Add a Password":"添加密码","Add an optional password to secure the recovery phrase":"添加可选的密码,以保护恢复短语","Add comment":"添加评论","Add wallet":"添加钱包","Address":"地址","Address Type":"地址类型","Advanced":"進階","Alias":"别名","Alias for {{index.walletName}}":"{{index.walletName}}别名","All contributions to Copay's translation are welcome. Sign up at crowdin.com and join the Copay project at":"欢迎大家为 Copay 提供翻译,注册 crowdin.com 并加入 Copay 项目","All transaction requests are irreversible.":"所有交易请求均不可逆。","Alternative Currency":"替代货币","Amount":"数额","Amount below minimum allowed":"数额低于最低允许值","Amount in":"已转换的数额","Are you sure you want to delete the recovery phrase?":"你确定要删除恢复短语吗?","Are you sure you want to delete this wallet?":"确定要删除这钱包?","Auditable":"可审核","Available Balance":"可用余额","Average confirmation time: {{fee.nbBlocks * 10}} minutes":"平均确认时间: {{fee.nbBlocks * 10}} 分钟","Back":"返回","Backup":"备份","Backup failed":"备份失败","Backup Needed":"需要备份","Backup now":"现在备份","Bad wallet invitation":"坏钱包邀请","Balance By Address":"地址余额","Before receiving funds, you must backup your wallet. If this device is lost, it is impossible to access your funds without a backup.":"接收资金前, 务必备份你的钱包。如果你遗失此设备,就无法在没有备份的情况下找回资金。","BETA: Android Key Derivation Test:":"BETA: Android 密钥衍生测试︰","BIP32 path for address derivation":"BIP32 路径的地址衍生","Bitcoin address":"比特币地址","Bitcoin Network Fee Policy":"比特币网络手续费策略","Bitcoin transactions may include a fee collected by miners on the network. The higher the fee, the greater the incentive a miner has to include that transaction in a block. Current fees are determined based on network load and the selected policy.":"比特币交易可能包括网络矿工所收取的费用。收费越高,交易数据块包含矿工的奖励也越大。当前收费的确定取决于网络负载和所选定的策略。","Bitcoin URI is NOT valid!":"比特币 URI 无效!","Broadcast Payment":"广播支付","Broadcasting transaction":"正在广播交易","Browser unsupported":"浏览器不被支持","Calculating fee":"正在计算费用","Cancel":"取消","Cancel and delete the wallet":"取消并删除钱包","Cannot create transaction. Insufficient funds":"不能创建交易。资金不足","Cannot join the same wallet more that once":"无法重复加入同一个钱包","Cannot sign: The payment request has expired":"无法签名︰支付请求已过期","Certified by":"通过认证:","Changing wallet alias only affects the local wallet name.":"更改钱包别名只会影响本地钱包名称。","Chinese":"中文","Choose a backup file from your computer":"从你的计算机选择一个备份文件","Clear cache":"清空缓存","Close":"关闭","Color":"颜色","Comment":"评论","Commit hash":"提交哈希","Confirm":"确定","Confirm your wallet recovery phrase":"确认你的钱包恢复短语","Confirmations":"确认","Congratulations!":"恭喜!","Connecting to Coinbase...":"正在连接 Coinbase...","Connecting to Glidera...":"正在连接 Glidera...","Connection reset by peer":"连接被对方重置","Continue":"继续","Copayer already in this wallet":"Copayer 已经在这个钱包里","Copayer already voted on this spend proposal":"Copayer 已经表决此花费提议","Copayer data mismatch":"Copayer 的数据不匹配","Copayers":"Copayers","Copied to clipboard":"已复制到剪贴板","Copy this text as it is to a safe place (notepad or email)":"将此文本复制到一个安全的地方(记事本或电子邮件)","Copy to clipboard":"复制到剪贴板","Could not access the wallet at the server. Please check:":"无法访问服务器上的钱包。请确认︰","Could not access wallet":"无法访问钱包","Could not access Wallet Service: Not found":"不能访问 Wallet Service︰ 找不到","Could not broadcast payment":"无法广播支付","Could not build transaction":"无法建立交易","Could not create address":"无法创建地址","Could not create payment proposal":"无法创建支付提议","Could not create using the specified extended private key":"无法使用指定的扩展私人密钥创建","Could not create using the specified extended public key":"无法使用指定的扩展的公钥创建","Could not create: Invalid wallet recovery phrase":"无法创建 ︰ 无效的钱包恢复短语","Could not decrypt file, check your password":"无法解密文件,请检查你的密码","Could not delete payment proposal":"无法删除支付提议","Could not fetch payment information":"无法获取支付信息","Could not get fee value":"无法获取手续费率","Could not import":"无法导入","Could not import. Check input file and spending password":"无法导入。请检查输入文件和支付密码","Could not join wallet":"无法加入钱包","Could not recognize a valid Bitcoin QR Code":"无法识别有效的比特币 QR 代码","Could not reject payment":"无法拒绝支付","Could not send payment":"无法发送支付","Could not update Wallet":"无法更新钱包","Create":"创建","Create {{requiredCopayers}}-of-{{totalCopayers}} wallet":"创建{{totalCopayers}}-的-{{requiredCopayers}} 的钱包","Create new wallet":"创建新钱包","Create, join or import":"创建、 加入或导入","Created by":"创建者:","Creating transaction":"正在创建交易","Creating Wallet...":"正在创建钱包...","Current fee rate for this policy: {{fee.feePerKBUnit}}/kiB":"此策略的当前收费率︰{{fee.feePerKBUnit}}/kiB","Czech":"捷克文","Date":"日期","Decrypting a paper wallet could take around 5 minutes on this device. please be patient and keep the app open.":"在此设备上解密纸钱包可能需要大约 5 分钟。请耐心等候并保持程序开着。","Delete it and create a new one":"删除并创建新的","Delete Payment Proposal":"删除支付提议","Delete recovery phrase":"删除恢复短语","Delete Recovery Phrase":"删除恢复短语","Delete wallet":"删除钱包","Delete Wallet":"删除钱包","Deleting Wallet...":"正在删除钱包...","Derivation Path":"衍生路径","Derivation Strategy":"衍生策略","Description":"说明","Details":"详细信息","Disabled":"未启用","Do not include private key":"不包括私钥","Don't see your language on Crowdin? Contact the Owner on Crowdin! We'd love to support your language.":"在 Crowdin 找不到你的语言?请联系 Crowdin 的所有者!我们很乐意支持你的语言。","Done":"完成","Download":"下载","Economy":"经济","Edit":"编辑","Edit comment":"编辑评论","Edited by":"编辑者:","Email for wallet notifications":"发送钱包通知到邮箱","Email Notifications":"邮箱通知","Empty addresses limit reached. New addresses cannot be generated.":"已达到空地址限制。无法生成新的地址。","Enable Coinbase Service":"启用 Coinbase 服务","Enable Glidera Service":"启用 Glidera 服务","Enable push notifications":"启用推式通知","Encrypted export file saved":"已保存加密的导出文件","Enter the recovery phrase (BIP39)":"输入恢复短语 (BIP39)","Enter your password":"请输入你的密码","Enter your spending password":"输入你的支付密码","Error at Wallet Service":"Wallet Service 出现错误","Error creating wallet":"创建钱包时出现错误","Expired":"已过期","Expires":"到期","Export options":"导出选项","Export to file":"导出到文件","Export Wallet":"导出钱包","Exporting via QR not supported for this wallet":"此钱包不支持通过 QR 的导出","Extended Public Keys":"扩展的公钥","Extracting Wallet Information...":"正在获取钱包信息...","Failed to export":"导出失败","Failed to verify backup. Please check your information":"验证备份失败。请检查你的信息","Family vacation funds":"家庭度假资金","Fee":"费用","Fetching Payment Information":"获取支付信息","File/Text":"文件/文本","Finger Scan Failed":"指纹扫描失败","Finish":"完成","For audit purposes":"供审计目的","French":"法语","From the destination device, go to Add wallet > Import wallet and scan this QR code":"从目标设备,请到添加钱包 > 导入钱包和扫描此 QR 代码","Funds are locked by pending spend proposals":"资金由未决的花费提议锁定","Funds found":"找到资金","Funds received":"收到的资金","Funds will be transferred to":"资金将会转移到","Generate new address":"生成新的地址","Generate QR Code":"生成 QR 码","Generating .csv file...":"正在生成 .csv 文件...","German":"德语","Getting address for wallet {{selectedWalletName}} ...":"获取{{selectedWalletName}} 钱包的地址...","Global preferences":"全局首选项","Hardware wallet":"硬件钱包","Hardware Wallet":"硬件钱包","Hide advanced options":"隐藏高级选项","I affirm that I have read, understood, and agree with these terms.":"我确定已阅读、理解并同意这些条款。","I AGREE. GET STARTED":"我同意。现即开始","Import":"导入","Import backup":"导入备份","Import wallet":"导入钱包","Importing Wallet...":"正在导入钱包...","In no event shall the authors of the software, employees and affiliates of Bitpay, copyright holders, or BitPay, Inc. be held 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.":"在任何情况下,软件作者、Bitpay 的员工及附属公司、版权持有人或 BitPay,Inc. 均不对由软件引起,与软件有关联或无关联,所任何索赔、损害或其他责任,无论是合同诉讼、侵权行为或其他,产生从本合同或与本软件有关。","In order to verify your wallet backup, please type your password:":"为了验证你的钱包备份,请键入你的密码:","Incorrect address network":"地址网络不正确","Incorrect code format":"代码格式不正确","Insufficient funds":"资金不足","Insufficient funds for fee":"费用的资金不足","Invalid":"无效","Invalid account number":"帐户号无效","Invalid address":"地址无效","Invalid derivation path":"衍生路径无效","Invitation to share a Copay Wallet":"邀请分享 Copay 钱包","Italian":"義大利文","Japanese":"日语","John":"John","Join":"加入","Join my Copay wallet. Here is the invitation code: {{secret}} You can download Copay for your phone or desktop at https://copay.io":"加入我的 Copay 钱包。这是邀请码 ︰ {{secret}} 你可以在 https://copay.io 下载 Copay 到你的手机或桌式电脑","Join shared wallet":"加入共享钱包","Joining Wallet...":"正在加入钱包...","Key already associated with an existing wallet":"钥已经关联现有的钱包","Label":"标签","Language":"语言","Last Wallet Addresses":"最后的钱包地址","Learn more about Copay backups":"了解更多关于 Copay 备份","Loading...":"正在加载...","locked by pending payments":"被未决支付锁定","Locktime in effect. Please wait to create a new spend proposal":"Locktime 在进行中。请稍等以创建新的花费提议","Locktime in effect. Please wait to remove this spend proposal":"Locktime 在进行中。请稍等以删除花费提议","Make a payment to":"支付给","Matches:":"匹配:","me":"我","Me":"我","Memo":"便签","Merchant message":"商家的消息","Message":"信息","Missing parameter":"缺失参数","Missing private keys to sign":"遗失需要签名的私钥","Moved":"已调动","Multiple recipients":"多个接收者","My Bitcoin address":"我的比特币地址","My contacts":"我的联系人","My wallets":"我的钱包","Need to do backup":"需要做备份","Network":"网络","Network connection error":"网络连接错误","New Payment Proposal":"新的支付提议","New Random Recovery Phrase":"新的随机恢复短语","No hardware wallets supported on this device":"此设备不支持硬件钱包","No transactions yet":"没有交易记录","Normal":"常规","Not authorized":"尚未授权","Not completed":"未完成","Not enough funds for fee":"费用的资金不足","Not valid":"无效","Note":"备注","Note: a total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded":"备注︰共有{{amountAboveMaxSizeStr}} 被排除了。超出了交易允许的最大体积","Note: a total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided.":"备注:共有{{amountBelowFeeStr}} 被排除了。这些来自 UTXOs 的资金小于提供的网络费用。","NOTE: To import a wallet from a 3rd party software, please go to Add Wallet > Create Wallet, and specify the Recovery Phrase there.":"注意︰欲从第三方软件导入钱包,请到添加钱包 > 创建钱包,并指定恢复短语。","Official English Disclaimer":"官方英文免责声明","OKAY":"OKAY","Once you have copied your wallet recovery phrase down, it is recommended to delete it from this device.":"一旦抄下你的钱包恢复短语,建议从此设备上删除。","Only Main (not change) addresses are shown. The addresses on this list were not verified locally at this time.":"只显示主要(不改变)的地址。这个时候不本地验证此列表上的地址。","Open Settings app":"打开设置应用","optional":"可选","Paper Wallet Private Key":"纸钱包私钥","Participants":"参与者","Passphrase":"密码短语","Password":"密码","Password required. Make sure to enter your password in advanced options":"需要密码。请务必在高级选项中输入你的密码","Paste invitation here":"在此粘贴邀请","Paste the backup plain text code":"粘贴备份的纯文本代码","Paste your paper wallet private key here":"在此粘贴你的纸钱包私钥","Pasted from clipboard":"自剪贴板粘贴","Pay To":"支付给","Payment Accepted":"已接受支付","Payment accepted, but not yet broadcasted":"支付已被接受,但尚未广播","Payment accepted. It will be broadcasted by Glidera. In case there is a problem, it can be deleted 6 hours after it was created.":"支付以被接受。它将由 Glidera 广播。如果出现问题,它可以在创建后的 6 个小时内删除。","Payment details":"支付明细","Payment expires":"支付期满","Payment Proposal":"支付提议","Payment Proposal Created":"支付提议已创建","Payment Proposal Rejected":"支付提议已被拒绝","Payment Proposal Rejected by Copayer":"支付提议已被 Copayer 拒绝","Payment Proposal Signed by Copayer":"支付提议已获 Copayer 签名","Payment Proposals":"支付提议","Payment Protocol Invalid":"支付协议无效","Payment Protocol not supported on Chrome App":"支付协议不支持 Chrome 应用程序","Payment Rejected":"支付被拒绝","Payment request":"支付请求","Payment Sent":"支付已发送","Payment to":"支付给","Pending Confirmation":"待确认","Permanently delete this wallet. THIS ACTION CANNOT BE REVERSED":"永久删除这个钱包。此操作无法撤消","Personal Wallet":"个人钱包","Please enter the recovery phrase":"请输入恢复短语","Please enter the required fields":"请输入必须填写的信息","Please enter the wallet recovery phrase":"请输入钱包恢复短语","Please tap the words in order to confirm your backup phrase is correctly written.":"请按顺序点击词句,以确认你的备份短语填写正确。","Please upgrade Copay to perform this action":"请升级 Copay 以执行此操作","Please wait to be redirected...":"请等待重新定向...","Please, select your backup file":"请选择你的备份文件","Polish":"波兰文","Preferences":"偏好","Preparing backup...":"正在准备备份...","preparing...":"准备中...","Press again to exit":"再按一次退出","Priority":"优先","Private key is encrypted, cannot sign":"私钥已加密,无法签名","Push notifications for Copay are currently disabled. Enable them in the Settings app.":"Copay 的推式通知目前未启用。请在设置应用里启用它。","QR Code":"QR 码","QR-Scanner":"QR-扫描仪","Receive":"接收","Received":"已接收","Recipients":"接收者","Recovery Phrase":"恢复短语","Recovery phrase deleted":"恢复短语已删除","Recreate":"重新创建","Recreating Wallet...":"正在重新创建的钱包...","Reject":"拒絕","Release Information":"发布信息","Remove":"移除","Repeat password":"重复输入密码","Repeat the password":"重复密码","Repeat the spending password":"重复支付密码","Request a specific amount":"请求特定数额","Request Spending Password":"请求支付密码","Required":"必需","Required number of signatures":"所需的签名数","Retrieving inputs information":"正在获取输入的信息。","Russian":"俄语","Save":"保存","Scan addresses for funds":"扫描资金的地址","Scan Fingerprint":"扫描指纹","Scan Finished":"扫描完成","Scan status finished with error":"扫描完成,出现错误","Scan Wallet Funds":"扫描钱包资金","Scan your fingerprint please":"请扫描你的指纹","Scanning Wallet funds...":"正在扫描钱包资金...","Search transactions":"搜索交易","Search Transactions":"搜索交易","Security preferences":"安全首选项","See it on the blockchain":"在区块链查看","Select a backup file":"选择备份文件","Select a wallet":"选择钱包","Self-signed Certificate":"自签名证书","Send":"发送","Send addresses by email":"通过电邮发送地址","Send bitcoin":"发送比特币","Send by email":"通过电邮发送","Send Max":"发送最大","Sending":"正在发送","Sending transaction":"正在发送交易","Sent":"已发送","Server response could not be verified":"无法验证服务器响应","Session log":"会话日志","SET":"设置","Set default url":"设置默认的 url","Set up a password":"设置密码","Set up a spending password":"设置支付密码","Setting up email notifications could weaken your privacy, if the wallet service provider is compromised. Information available to an attacker would include your wallet addresses and its balance, but no more.":"设置电邮通知可能会削弱你的隐私,如果钱包服务提供商受到损害。攻击者可能获得的信息包括你的钱包地址及其结余,可仅此而已。","Settings":"设置","Share address":"共享地址","Share invitation":"共享邀请","Share this invitation with your copayers":"将此邀请与你的 copayers 共享","Share this wallet address to receive payments":"分享此钱包地址,以接收付款","Share this wallet address to receive payments. To protect your privacy, new addresses are generated automatically once you use them.":"共享此钱包地址,以便接收支付。为了保护你的隐私,一旦你使用它们,新地址将自动生成。","Shared Wallet":"共享的钱包","Show advanced options":"显示高级选项","Signatures rejected by server":"签名被服务器拒绝","Signing transaction":"签名交易","Single Address Wallet":"单一地址钱包","Spanish":"西班牙语","Specify Recovery Phrase...":"指定恢复短语......","Spend proposal is not accepted":"花费提议不被接受","Spend proposal not found":"找不到花费提议","Spending Password needed":"需要支付密码","Spending Passwords do not match":"支付密码不匹配","Success":"成功","Super Economy":"超级经济","Sweep paper wallet":"Sweep 纸钱包","Sweep Wallet":"Sweep 钱包","Sweeping Wallet...":"正在导出钱包","Tap and hold to show":"点击并按住以显示","Tap to retry":"点击以重试","Terms of Use":"使用条款","The authors of the software, employees and affiliates of Bitpay, copyright holders, and BitPay, Inc. cannot retrieve your private keys or passwords if you lose or forget them and cannot guarantee transaction confirmation as they do not have control over the Bitcoin network.":"如果你遗失或忘记私钥或密码,软件作者、Bitpay 的员工及附属公司、版权持有人或 BitPay,Inc. 均无法取回你的私钥或密码,由于他们没有比特币网络的管理权,他们并不能保证交易确认。","The derivation path":"衍生路径","The Ledger Chrome application is not installed":"Ledger Chrome 应用程序未安装","The password of the recovery phrase (if set)":"恢复短语的密码 (如已设置)","The payment was created but could not be completed. Please try again from home screen":"支付已创建,但无法完成。请从首页再试一次","The payment was removed by creator":"支付已被创建者移除","The recovery phrase could require a password to be imported":"恢复短语需要密码才能导入","The request could not be understood by the server":"服务器不理解此请求","The software does not constitute an account where BitPay or other third parties serve as financial intermediaries or custodians of your bitcoin.":"此软件并不构成一个账户,让 BitPay 或其他第三方作为金融中介机构或保管人以保管你的比特币。","The software you are about to use functions as a free, open source, and multi-signature digital wallet.":"你将使用的软件是一个免费、开放源代码和多重签名的数字钱包。","The spend proposal is not pending":"花费提议不是未决","The wallet \"{{walletName}}\" was deleted":"\"{{walletName}}\"钱包已删除","The Wallet Recovery Phrase could require a password to be imported":"钱包恢复短语需要密码才能导入","The wallet service URL":"钱包服务 URL","There are no wallets to make this payment":"没有钱包以进行此支付","There is a new version of Copay. Please update":"Copay 有新版本。请更新","There is an error in the form":"表格中有错误","This recovery phrase was created with a password. To recover this wallet both the recovery phrase and password are needed.":"此恢复短语是用密码创建。为了恢复此钱包,需要恢复短语和密码。","This transaction has become invalid; possibly due to a double spend attempt.":"此交易已无效; 可能是双花尝试导致。","This wallet is not registered at the given Bitcore Wallet Service (BWS). You can recreate it from the local information.":"此钱包不在给定的 Bitcore Wallet Service (BWS) 注册。你可以从本地信息重新创建它。","Time":"时间","To":"发送到","To restore this {{index.m}}-{{index.n}} shared wallet you will need":"要恢复此 {{index.m}}{{index.n}} 共享 钱包,你需要","To the fullest extent permitted by law, this software is provided “as is” and no representations or warranties can be made of any kind, express or implied, including but not limited to the warranties of merchantability, fitness or a particular purpose and noninfringement.":"在法律允许的最大范围内,本软件“按原样”提供,不提供任何形式、明示 或暗示的担保或陈述,包括但不是限于商品适销性,针对特定目的的适用性或非侵害性的保证。","too long!":"太长了 !","Total Locked Balance":"锁定结余的总额","Total number of copayers":"Copayers 的总数","Touch ID Failed":"触摸 ID 失败","Transaction":"交易","Transaction already broadcasted":"交易已经广播","Transaction History":"交易历史记录","Translation Credits":"翻译志愿者","Translators":"翻译者","Try again":"重新尝试","Type the Recovery Phrase (usually 12 words)":"键入恢复短语 (通常 12 个字)","Unconfirmed":"未确认","Unit":"单位","Unsent transactions":"未发送的交易","Updating transaction history. Please stand by.":"更新交易历史记录。请等待。","Updating Wallet...":"正在更新钱包...","Use Unconfirmed Funds":"使用未经确认的资金","Validating recovery phrase...":"正在验证恢复短语。。。","Validating wallet integrity...":"正在验证钱包完整性。。。","Version":"版本","View":"查看","Waiting for copayers":"正在等待 copayers","Waiting for Ledger...":"正在等待 Ledger...","Waiting for Trezor...":"正在等待 Trezor...","Waiting...":"等待中...","Wallet already exists":"钱包已存在","Wallet already in Copay":"钱包已经在 Copay","Wallet Configuration (m-n)":"钱包配置 (m n)","Wallet Export":"钱包导出","Wallet Id":"钱包 Id","Wallet incomplete and broken":"钱包不完整和损坏","Wallet Information":"钱包信息","Wallet Invitation":"钱包邀请","Wallet Invitation is not valid!":"钱包邀请无效!","Wallet is full":"钱包已满","Wallet is locked":"钱包被锁定","Wallet is not complete":"钱包不完整","Wallet name":"钱包名称","Wallet Name (at creation)":"钱包名称(在创建时)","Wallet needs backup":"钱包需要备份","Wallet Network":"钱包网","Wallet not found":"找不到钱包","Wallet not registered at the wallet service. Recreate it from \"Create Wallet\" using \"Advanced Options\" to set your recovery phrase":"钱包不在 Wallet Service 注册。使用“创建钱包\"的\"高级选项\"设置你的恢复短语以重新创建它","Wallet Preferences":"钱包首选项","Wallet Recovery Phrase":"钱包恢复短语","Wallet Recovery Phrase is invalid":"无效的钱包恢复短语","Wallet recovery phrase not available. You can still export it from Advanced > Export.":"没有可用的钱包恢复短语。你仍然可以从 Advanced > Export 中导出。","Wallet service not found":"找不到 Wallet Service","WARNING: Key derivation is not working on this device/wallet. Actions cannot be performed on this wallet.":"警告︰此设备/钱包无法运行钥匙衍生。无法在此钱包上执行操作。","WARNING: Not including the private key allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"警告︰不包括私钥,以检查钱包余额、交易历史记录,及从导出创建开销提议。可是,不允许批准(签名)提议,因此 资金将无法从导出访问。","WARNING: The password cannot be recovered. Be sure to write it down. The wallet can not be restored without the password.":"警告︰密码不能恢复。必须要把它抄写下来。如果没有密码,钱包无法恢复。","WARNING: The private key of this wallet is not available. The export allows to check the wallet balance, transaction history, and create spend proposals from the export. However, does not allow to approve (sign) proposals, so funds will not be accessible from the export.":"警告︰此钱包没有可用的私钥。导出可以检查钱包余额、交易历史记录,及从导出创建开销提议。可是,不允许批准(签名)提议,因此 资金将无法从导出访问。","Warning: this transaction has unconfirmed inputs":"警告︰此交易有未经确认的输入","WARNING: UNTRUSTED CERTIFICATE":"警告︰不受信任的证书","WARNING: Wallet not registered":"警告 ︰ 钱包没有注册","Warning!":"警告!​​​​​","We reserve the right to modify this disclaimer from time to time.":"我们保留权利以修改此免责声明。","WELCOME TO COPAY":"欢迎使用 COPAY","While the software has undergone beta testing and continues to be improved by feedback from the open-source user and developer community, we cannot guarantee that there will be no bugs in the software.":"虽然软件经历了 beta 测试,并持续获得开源用户和开发者社区的反馈而改进,我们无法保证软件没有错误。","Write your wallet recovery phrase":"抄写下你的钱包恢复短语","Wrong number of recovery words:":"恢复词句数不正确:","Wrong spending password":"支付密码错误","Yes":"是","You acknowledge that your use of this software is at your own discretion and in compliance with all applicable laws.":"你承认和同意使用此软件是你自己的判断,并遵守所有适用法律。","You are responsible for safekeeping your passwords, private key pairs, PINs and any other codes you use to access the software.":"你有责任保管你的密码、私钥对,PINs 及你用以访问软件的任何其他代码。","You assume any and all risks associated with the use of the software.":"你承担使用本软件的任何和所有相关风险。","You backed up your wallet. You can now restore this wallet at any time.":"你已备份了钱包。你现在可以在任何时候复原此钱包。","You can safely install your wallet on another device and use it from multiple devices at the same time.":"你可以安全地在另一台设备上安装你的钱包,并同时在多个设备上使用。","You do not have any wallet":"你没有任何钱包","You need the wallet recovery phrase to restore this personal wallet. Write it down and keep them somewhere safe.":"你需要钱包恢复短语以恢复此个人钱包。把它抄写下来,并存放在安全的地方。","Your nickname":"你的昵称","Your password":"你的密码","Your spending password":"你的支付密码","Your wallet has been imported correctly":"你的钱包已正确导入","Your wallet key will be encrypted. The Spending Password cannot be recovered. Be sure to write it down":"你的钱包钥匙将被加密。支付密码不能恢复。必须把它抄写下来","Your wallet recovery phrase and access to the server that coordinated the initial wallet creation. You still need {{index.m}} keys to spend.":"你的钱包恢复短语及访问协调初始钱包创建的服务器。你仍然需要 {{index.m}} 钥匙来支付。"}); -/* jshint +W100 */ -}]); -window.version="2.4.1"; -window.commitHash="ade8d14"; -'use strict'; - -angular.element(document).ready(function() { - - // Run copayApp after device is ready. - var startAngular = function() { - angular.bootstrap(document, ['copayApp']); - }; - - - function handleOpenURL(url) { - if ('cordova' in window) { - console.log('DEEP LINK:' + url); - cordova.fireDocumentEvent('handleopenurl', { - url: url - }); - } else { - console.log("ERROR: Cannont handle open URL in non-cordova apps") - } - }; - - /* Cordova specific Init */ - if ('cordova' in window) { - - window.handleOpenURL = handleOpenURL; - - - document.addEventListener('deviceready', function() { - - // Create a sticky event for handling the app being opened via a custom URL - cordova.addStickyDocumentEventHandler('handleopenurl'); - startAngular(); - }, false); - - } else { - startAngular(); - } - -}); - -window.TREZOR_CHROME_URL = './bower_components/trezor-connect/chrome/wrapper.html'; - - -this.TrezorConnect = (function () { - 'use strict'; - - var chrome = window.chrome; - var IS_CHROME_APP = chrome && chrome.app && chrome.app.window; - - var ERR_TIMED_OUT = 'Loading timed out'; - var ERR_WINDOW_CLOSED = 'Window closed'; - var ERR_WINDOW_BLOCKED = 'Window blocked'; - var ERR_ALREADY_WAITING = 'Already waiting for a response'; - var ERR_CHROME_NOT_CONNECTED = 'Internal Chrome popup is not responding.'; - - var DISABLE_LOGIN_BUTTONS = window.TREZOR_DISABLE_LOGIN_BUTTONS || false; - var CHROME_URL = window.TREZOR_CHROME_URL || './chrome/wrapper.html'; - var POPUP_URL = window.TREZOR_POPUP_URL || 'https://trezor.github.io/connect/popup/popup.html'; - var POPUP_PATH = window.TREZOR_POPUP_PATH || 'https://trezor.github.io/connect/'; - var POPUP_ORIGIN = window.TREZOR_POPUP_ORIGIN || 'https://trezor.github.io'; - - var POPUP_INIT_TIMEOUT = 15000; - - /** - * Public API. - */ - function TrezorConnect() { - - var manager = new PopupManager(); - - /** - * Popup errors. - */ - this.ERR_TIMED_OUT = ERR_TIMED_OUT; - this.ERR_WINDOW_CLOSED = ERR_WINDOW_CLOSED; - this.ERR_WINDOW_BLOCKED = ERR_WINDOW_BLOCKED; - this.ERR_ALREADY_WAITING = ERR_ALREADY_WAITING; - this.ERR_CHROME_NOT_CONNECTED = ERR_CHROME_NOT_CONNECTED; - - /** - * @param {boolean} value - */ - this.closeAfterSuccess = function (value) { manager.closeAfterSuccess = value; }; - - /** - * @param {boolean} value - */ - this.closeAfterFailure = function (value) { manager.closeAfterFailure = value; }; - - /** - * @typedef XPubKeyResult - * @param {boolean} success - * @param {?string} error - * @param {?string} xpubkey serialized extended public key - * @param {?string} path BIP32 serializd path of the key - */ - - /** - * Load BIP32 extended public key by path. - * - * Path can be specified either in the string form ("m/44'/1/0") or as - * raw integer array. In case you omit the path, user is asked to select - * a BIP32 account to export, and the result contains m/44'/0'/x' node - * of the account. - * - * @param {?(string|array)} path - * @param {function(XPubKeyResult)} callback - */ - this.getXPubKey = function (path, callback) { - if (typeof path === 'string') { - path = parseHDPath(path); - } - manager.sendWithChannel({ - type: 'xpubkey', - path: path - }, callback); - }; - - /** - * @typedef SignTxResult - * @param {boolean} success - * @param {?string} error - * @param {?string} serialized_tx serialized tx, in hex, including signatures - * @param {?array} signatures array of input signatures, in hex - */ - - /** - * Sign a transaction in the device and return both serialized - * transaction and the signatures. - * - * @param {array} inputs - * @param {array} outputs - * @param {function(SignTxResult)} callback - * - * @see https://github.com/trezor/trezor-common/blob/master/protob/types.proto - */ - this.signTx = function (inputs, outputs, callback) { - manager.sendWithChannel({ - type: 'signtx', - inputs: inputs, - outputs: outputs - }, callback); - }; - - /** - * @typedef TxRecipient - * @param {number} amount the amount to send, in satoshis - * @param {string} address the address of the recipient - */ - - /** - * Compose a transaction by doing BIP-0044 discovery, letting the user - * select an account, and picking UTXO by internal preferences. - * Transaction is then signed and returned in the same format as - * `signTx`. Only supports BIP-0044 accounts (single-signature). - * - * @param {array} recipients - * @param {function(SignTxResult)} callback - */ - this.composeAndSignTx = function (recipients, callback) { - manager.sendWithChannel({ - type: 'composetx', - recipients: recipients - }, callback); - }; - - /** - * @typedef RequestLoginResult - * @param {boolean} success - * @param {?string} error - * @param {?string} public_key public key used for signing, in hex - * @param {?string} signature signature, in hex - */ - - /** - * Sign a login challenge for active origin. - * - * @param {?string} hosticon - * @param {string} challenge_hidden - * @param {string} challenge_visual - * @param {string|function(RequestLoginResult)} callback - * - * @see https://github.com/trezor/trezor-common/blob/master/protob/messages.proto - */ - this.requestLogin = function ( - hosticon, - challenge_hidden, - challenge_visual, - callback - ) { - if (typeof callback === 'string') { - // special case for a login through button. - // `callback` is name of global var - callback = window[callback]; - } - if (!callback) { - throw new TypeError('TrezorConnect: login callback not found'); - } - manager.sendWithChannel({ - type: 'login', - icon: hosticon, - challenge_hidden: challenge_hidden, - challenge_visual: challenge_visual - }, callback); - }; - - var LOGIN_CSS = - ''; - - var LOGIN_ONCLICK = - 'TrezorConnect.requestLogin(' - + "'@hosticon@','@challenge_hidden@','@challenge_visual@','@callback@'" - + ')'; - - var LOGIN_HTML = - '
' - + ' ' - + ' ' - + ' @text@' - + ' ' - + ' ' - + ' What is TREZOR?' - + ' ' - + '
'; - - /** - * Find elements and replace them with login buttons. - * It's not required to use these special elements, feel free to call - * `TrezorConnect.requestLogin` directly. - */ - this.renderLoginButtons = function () { - var elements = document.getElementsByTagName('trezor:login'); - - for (var i = 0; i < elements.length; i++) { - var e = elements[i]; - var text = e.getAttribute('text') || 'Sign in with TREZOR'; - var callback = e.getAttribute('callback') || ''; - var hosticon = e.getAttribute('icon') || ''; - var challenge_hidden = e.getAttribute('challenge_hidden') || ''; - var challenge_visual = e.getAttribute('challenge_visual') || ''; - - // it's not valid to put markup into attributes, so let users - // supply a raw text and make TREZOR bold - text = text.replace('TREZOR', 'TREZOR'); - - e.parentNode.innerHTML = - (LOGIN_CSS + LOGIN_HTML) - .replace('@text@', text) - .replace('@callback@', callback) - .replace('@hosticon@', hosticon) - .replace('@challenge_hidden@', challenge_hidden) - .replace('@challenge_visual@', challenge_visual) - .replace('@connect_path@', POPUP_PATH); - } - }; - } - - /* - * `getXPubKey()` - */ - - function parseHDPath(string) { - return string - .toLowerCase() - .split('/') - .filter(function (p) { return p !== 'm'; }) - .map(function (p) { - var n = parseInt(p); - if (p[p.length - 1] === "'") { // hardened index - n = n | 0x80000000; - } - return n; - }); - } - - /* - * Popup management - */ - - function ChromePopup(url, name, width, height) { - var left = (screen.width - width) / 2; - var top = (screen.height - height) / 2; - var opts = { - id: name, - innerBounds: { - width: width, - height: height, - left: left, - top: top - } - }; - - var closed = function () { - if (this.onclose) { - this.onclose(false); // never report as blocked - } - }.bind(this); - - var opened = function (w) { - this.window = w; - this.window.onClosed.addListener(closed); - }.bind(this); - - chrome.app.window.create(url, opts, opened); - - this.name = name; - this.window = null; - this.onclose = null; - } - - function ChromeChannel(popup, waiting) { - var port = null; - - var respond = function (data) { - if (waiting) { - var w = waiting; - waiting = null; - w(data); - } - }; - - var setup = function (p) { - if (p.name === popup.name) { - port = p; - port.onMessage.addListener(respond); - chrome.runtime.onConnect.removeListener(setup); - } - }; - - chrome.runtime.onConnect.addListener(setup); - - this.respond = respond; - - this.close = function () { - chrome.runtime.onConnect.removeListener(setup); - port.onMessage.removeListener(respond); - port.disconnect(); - port = null; - }; - - this.send = function (value, callback) { - if (waiting === null) { - waiting = callback; - - if (port) { - port.postMessage(value); - } else { - throw new Error(ERR_CHROME_NOT_CONNECTED); - } - } else { - throw new Error(ERR_ALREADY_WAITING); - } - }; - } - - function Popup(url, origin, name, width, height) { - var left = (screen.width - width) / 2; - var top = (screen.height - height) / 2; - var opts = - 'width=' + width + - ',height=' + height + - ',left=' + left + - ',top=' + top + - ',menubar=no' + - ',toolbar=no' + - ',location=no' + - ',personalbar=no' + - ',status=no'; - var w = window.open(url, name, opts); - - var interval; - var blocked = w.closed; - var iterate = function () { - if (w.closed) { - clearInterval(interval); - if (this.onclose) { - this.onclose(blocked); - } - } - }.bind(this); - interval = setInterval(iterate, 100); - - this.window = w; - this.origin = origin; - this.onclose = null; - } - - function Channel(popup, waiting) { - - var respond = function (data) { - if (waiting) { - var w = waiting; - waiting = null; - w(data); - } - }; - - var receive = function (event) { - if (event.source === popup.window && event.origin === popup.origin) { - respond(event.data); - } - }; - - window.addEventListener('message', receive); - - this.respond = respond; - - this.close = function () { - window.removeEventListener('message', receive); - }; - - this.send = function (value, callback) { - if (waiting === null) { - waiting = callback; - popup.window.postMessage(value, popup.origin); - } else { - throw new Error(ERR_ALREADY_WAITING); - } - }; - } - - function ConnectedChannel(p) { - - var ready = function () { - clearTimeout(this.timeout); - this.popup.onclose = null; - this.ready = true; - this.onready(); - }.bind(this); - - var closed = function (blocked) { - clearTimeout(this.timeout); - this.channel.close(); - if (blocked) { - this.onerror(new Error(ERR_WINDOW_BLOCKED)); - } else { - this.onerror(new Error(ERR_WINDOW_CLOSED)); - } - }.bind(this); - - var timedout = function () { - this.popup.onclose = null; - if (this.popup.window) { - this.popup.window.close(); - } - this.channel.close(); - this.onerror(new Error(ERR_TIMED_OUT)); - }.bind(this); - - if (IS_CHROME_APP) { - this.popup = new ChromePopup(p.chromeUrl, p.name, p.width, p.height); - this.channel = new ChromeChannel(this.popup, ready); - } else { - this.popup = new Popup(p.url, p.origin, p.name, p.width, p.height); - this.channel = new Channel(this.popup, ready); - } - - this.timeout = setTimeout(timedout, POPUP_INIT_TIMEOUT); - - this.popup.onclose = closed; - - this.ready = false; - this.onready = null; - this.onerror = null; - } - - function PopupManager() { - var cc = null; - - var closed = function () { - cc.channel.respond(new Error(ERR_WINDOW_CLOSED)); - cc.channel.close(); - cc = null; - }; - - var open = function (callback) { - cc = new ConnectedChannel({ - name: 'trezor-connect', - width: 600, - height: 500, - origin: POPUP_ORIGIN, - path: POPUP_PATH, - url: POPUP_URL, - chromeUrl: CHROME_URL - }); - cc.onready = function () { - cc.popup.onclose = closed; - callback(cc.channel); - }; - cc.onerror = function (error) { - cc = null; - callback(error); - }; - }.bind(this); - - this.closeAfterSuccess = true; - this.closeAfterFailure = true; - - this.close = function () { - if (cc && cc.popup.window) { - cc.popup.window.close(); - } - }; - - this.waitForChannel = function (callback) { - if (cc) { - if (cc.ready) { - callback(cc.channel); - } else { - callback(new Error(ERR_ALREADY_WAITING)); - } - } else { - open(callback); - } - }; - - this.sendWithChannel = function (message, callback) { - - var respond = function (response) { - var succ = response.success && this.closeAfterSuccess; - var fail = !response.success && this.closeAfterFailure; - if (succ || fail) { - this.close(); - } - callback(response); - }.bind(this); - - var onresponse = function (response) { - if (response instanceof Error) { - var error = response; - respond({ success: false, error: error.message }); - } else { - respond(response); - } - }; - - var onchannel = function (channel) { - if (channel instanceof Error) { - var error = channel; - respond({ success: false, error: error.message }); - } else { - channel.send(message, onresponse); - } - }; - - this.waitForChannel(onchannel); - }; - } - - var exports = new TrezorConnect(); - - if (!IS_CHROME_APP && !DISABLE_LOGIN_BUTTONS) { - exports.renderLoginButtons(); - } - - return exports; - -}()); diff --git a/browser-extensions/chrome/copay-chrome-extension/js/directives.js b/browser-extensions/chrome/copay-chrome-extension/js/directives.js deleted file mode 100644 index ad9a93a7c..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/js/directives.js +++ /dev/null @@ -1 +0,0 @@ -'use strict'; diff --git a/browser-extensions/chrome/copay-chrome-extension/js/filters.js b/browser-extensions/chrome/copay-chrome-extension/js/filters.js deleted file mode 100644 index ad9a93a7c..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/js/filters.js +++ /dev/null @@ -1 +0,0 @@ -'use strict'; diff --git a/browser-extensions/chrome/copay-chrome-extension/js/init.js b/browser-extensions/chrome/copay-chrome-extension/js/init.js deleted file mode 100644 index cd0922afc..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/js/init.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -angular.element(document).ready(function() { - // Init the app - // angular.bootstrap(document, ['cosign']); -}); diff --git a/browser-extensions/chrome/copay-chrome-extension/lib/angular.js b/browser-extensions/chrome/copay-chrome-extension/lib/angular.js deleted file mode 100644 index 14f66f240..000000000 --- a/browser-extensions/chrome/copay-chrome-extension/lib/angular.js +++ /dev/null @@ -1,157450 +0,0 @@ -//--------------------------------------------------------------------- -// -// QR Code Generator for JavaScript -// -// Copyright (c) 2009 Kazuhiko Arase -// -// URL: http://www.d-project.com/ -// -// Licensed under the MIT license: -// http://www.opensource.org/licenses/mit-license.php -// -// The word 'QR Code' is registered trademark of -// DENSO WAVE INCORPORATED -// http://www.denso-wave.com/qrcode/faqpatent-e.html -// -//--------------------------------------------------------------------- - -var qrcode = function() { - - //--------------------------------------------------------------------- - // qrcode - //--------------------------------------------------------------------- - - /** - * qrcode - * @param typeNumber 1 to 40 - * @param errorCorrectLevel 'L','M','Q','H' - */ - var qrcode = function(typeNumber, errorCorrectLevel) { - - var PAD0 = 0xEC; - var PAD1 = 0x11; - - var _typeNumber = typeNumber; - var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel]; - var _modules = null; - var _moduleCount = 0; - var _dataCache = null; - var _dataList = new Array(); - - var _this = {}; - - var makeImpl = function(test, maskPattern) { - - _moduleCount = _typeNumber * 4 + 17; - _modules = function(moduleCount) { - var modules = new Array(moduleCount); - for (var row = 0; row < moduleCount; row += 1) { - modules[row] = new Array(moduleCount); - for (var col = 0; col < moduleCount; col += 1) { - modules[row][col] = null; - } - } - return modules; - }(_moduleCount); - - setupPositionProbePattern(0, 0); - setupPositionProbePattern(_moduleCount - 7, 0); - setupPositionProbePattern(0, _moduleCount - 7); - setupPositionAdjustPattern(); - setupTimingPattern(); - setupTypeInfo(test, maskPattern); - - if (_typeNumber >= 7) { - setupTypeNumber(test); - } - - if (_dataCache == null) { - _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList); - } - - mapData(_dataCache, maskPattern); - }; - - var setupPositionProbePattern = function(row, col) { - - for (var r = -1; r <= 7; r += 1) { - - if (row + r <= -1 || _moduleCount <= row + r) continue; - - for (var c = -1; c <= 7; c += 1) { - - if (col + c <= -1 || _moduleCount <= col + c) continue; - - if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) - || (0 <= c && c <= 6 && (r == 0 || r == 6) ) - || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { - _modules[row + r][col + c] = true; - } else { - _modules[row + r][col + c] = false; - } - } - } - }; - - var getBestMaskPattern = function() { - - var minLostPoint = 0; - var pattern = 0; - - for (var i = 0; i < 8; i += 1) { - - makeImpl(true, i); - - var lostPoint = QRUtil.getLostPoint(_this); - - if (i == 0 || minLostPoint > lostPoint) { - minLostPoint = lostPoint; - pattern = i; - } - } - - return pattern; - }; - - var setupTimingPattern = function() { - - for (var r = 8; r < _moduleCount - 8; r += 1) { - if (_modules[r][6] != null) { - continue; - } - _modules[r][6] = (r % 2 == 0); - } - - for (var c = 8; c < _moduleCount - 8; c += 1) { - if (_modules[6][c] != null) { - continue; - } - _modules[6][c] = (c % 2 == 0); - } - }; - - var setupPositionAdjustPattern = function() { - - var pos = QRUtil.getPatternPosition(_typeNumber); - - for (var i = 0; i < pos.length; i += 1) { - - for (var j = 0; j < pos.length; j += 1) { - - var row = pos[i]; - var col = pos[j]; - - if (_modules[row][col] != null) { - continue; - } - - for (var r = -2; r <= 2; r += 1) { - - for (var c = -2; c <= 2; c += 1) { - - if (r == -2 || r == 2 || c == -2 || c == 2 - || (r == 0 && c == 0) ) { - _modules[row + r][col + c] = true; - } else { - _modules[row + r][col + c] = false; - } - } - } - } - } - }; - - var setupTypeNumber = function(test) { - - var bits = QRUtil.getBCHTypeNumber(_typeNumber); - - for (var i = 0; i < 18; i += 1) { - var mod = (!test && ( (bits >> i) & 1) == 1); - _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod; - } - - for (var i = 0; i < 18; i += 1) { - var mod = (!test && ( (bits >> i) & 1) == 1); - _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod; - } - }; - - var setupTypeInfo = function(test, maskPattern) { - - var data = (_errorCorrectLevel << 3) | maskPattern; - var bits = QRUtil.getBCHTypeInfo(data); - - // vertical - for (var i = 0; i < 15; i += 1) { - - var mod = (!test && ( (bits >> i) & 1) == 1); - - if (i < 6) { - _modules[i][8] = mod; - } else if (i < 8) { - _modules[i + 1][8] = mod; - } else { - _modules[_moduleCount - 15 + i][8] = mod; - } - } - - // horizontal - for (var i = 0; i < 15; i += 1) { - - var mod = (!test && ( (bits >> i) & 1) == 1); - - if (i < 8) { - _modules[8][_moduleCount - i - 1] = mod; - } else if (i < 9) { - _modules[8][15 - i - 1 + 1] = mod; - } else { - _modules[8][15 - i - 1] = mod; - } - } - - // fixed module - _modules[_moduleCount - 8][8] = (!test); - }; - - var mapData = function(data, maskPattern) { - - var inc = -1; - var row = _moduleCount - 1; - var bitIndex = 7; - var byteIndex = 0; - var maskFunc = QRUtil.getMaskFunction(maskPattern); - - for (var col = _moduleCount - 1; col > 0; col -= 2) { - - if (col == 6) col -= 1; - - while (true) { - - for (var c = 0; c < 2; c += 1) { - - if (_modules[row][col - c] == null) { - - var dark = false; - - if (byteIndex < data.length) { - dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); - } - - var mask = maskFunc(row, col - c); - - if (mask) { - dark = !dark; - } - - _modules[row][col - c] = dark; - bitIndex -= 1; - - if (bitIndex == -1) { - byteIndex += 1; - bitIndex = 7; - } - } - } - - row += inc; - - if (row < 0 || _moduleCount <= row) { - row -= inc; - inc = -inc; - break; - } - } - } - }; - - var createBytes = function(buffer, rsBlocks) { - - var offset = 0; - - var maxDcCount = 0; - var maxEcCount = 0; - - var dcdata = new Array(rsBlocks.length); - var ecdata = new Array(rsBlocks.length); - - for (var r = 0; r < rsBlocks.length; r += 1) { - - var dcCount = rsBlocks[r].dataCount; - var ecCount = rsBlocks[r].totalCount - dcCount; - - maxDcCount = Math.max(maxDcCount, dcCount); - maxEcCount = Math.max(maxEcCount, ecCount); - - dcdata[r] = new Array(dcCount); - - for (var i = 0; i < dcdata[r].length; i += 1) { - dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; - } - offset += dcCount; - - var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); - var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1); - - var modPoly = rawPoly.mod(rsPoly); - ecdata[r] = new Array(rsPoly.getLength() - 1); - for (var i = 0; i < ecdata[r].length; i += 1) { - var modIndex = i + modPoly.getLength() - ecdata[r].length; - ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0; - } - } - - var totalCodeCount = 0; - for (var i = 0; i < rsBlocks.length; i += 1) { - totalCodeCount += rsBlocks[i].totalCount; - } - - var data = new Array(totalCodeCount); - var index = 0; - - for (var i = 0; i < maxDcCount; i += 1) { - for (var r = 0; r < rsBlocks.length; r += 1) { - if (i < dcdata[r].length) { - data[index] = dcdata[r][i]; - index += 1; - } - } - } - - for (var i = 0; i < maxEcCount; i += 1) { - for (var r = 0; r < rsBlocks.length; r += 1) { - if (i < ecdata[r].length) { - data[index] = ecdata[r][i]; - index += 1; - } - } - } - - return data; - }; - - var createData = function(typeNumber, errorCorrectLevel, dataList) { - - var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); - - var buffer = qrBitBuffer(); - - for (var i = 0; i < dataList.length; i += 1) { - var data = dataList[i]; - buffer.put(data.getMode(), 4); - buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) ); - data.write(buffer); - } - - // calc num max data. - var totalDataCount = 0; - for (var i = 0; i < rsBlocks.length; i += 1) { - totalDataCount += rsBlocks[i].dataCount; - } - - if (buffer.getLengthInBits() > totalDataCount * 8) { - throw new Error('code length overflow. (' - + buffer.getLengthInBits() - + '>' - + totalDataCount * 8 - + ')'); - } - - // end code - if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { - buffer.put(0, 4); - } - - // padding - while (buffer.getLengthInBits() % 8 != 0) { - buffer.putBit(false); - } - - // padding - while (true) { - - if (buffer.getLengthInBits() >= totalDataCount * 8) { - break; - } - buffer.put(PAD0, 8); - - if (buffer.getLengthInBits() >= totalDataCount * 8) { - break; - } - buffer.put(PAD1, 8); - } - - return createBytes(buffer, rsBlocks); - }; - - _this.addData = function(data) { - var newData = qr8BitByte(data); - _dataList.push(newData); - _dataCache = null; - }; - - _this.isDark = function(row, col) { - if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) { - throw new Error(row + ',' + col); - } - return _modules[row][col]; - }; - - _this.getModuleCount = function() { - return _moduleCount; - }; - - _this.make = function() { - makeImpl(false, getBestMaskPattern() ); - }; - - _this.createTableTag = function(cellSize, margin) { - - cellSize = cellSize || 2; - margin = (typeof margin == 'undefined')? cellSize * 4 : margin; - - var qrHtml = ''; - - qrHtml += ''; - qrHtml += ''; - - for (var r = 0; r < _this.getModuleCount(); r += 1) { - - qrHtml += ''; - - for (var c = 0; c < _this.getModuleCount(); c += 1) { - qrHtml += ''; - } - - qrHtml += ''; - qrHtml += '
'; - } - - qrHtml += '
'; - - return qrHtml; - }; - - _this.createSvgTag = function(cellSize, margin) { - - cellSize = cellSize || 2; - margin = (typeof margin == 'undefined')? cellSize * 4 : margin; - var size = _this.getModuleCount() * cellSize + margin * 2; - var c, mc, r, mr, qrSvg='', rect; - - rect = 'l' + cellSize + ',0 0,' + cellSize + - ' -' + cellSize + ',0 0,-' + cellSize + 'z '; - - qrSvg += '>> 8); - bytes.push(b & 0xff); - } - } else { - bytes.push(unknownChar); - } - } - } - return bytes; - }; - }; - - //--------------------------------------------------------------------- - // QRMode - //--------------------------------------------------------------------- - - var QRMode = { - MODE_NUMBER : 1 << 0, - MODE_ALPHA_NUM : 1 << 1, - MODE_8BIT_BYTE : 1 << 2, - MODE_KANJI : 1 << 3 - }; - - //--------------------------------------------------------------------- - // QRErrorCorrectLevel - //--------------------------------------------------------------------- - - var QRErrorCorrectLevel = { - L : 1, - M : 0, - Q : 3, - H : 2 - }; - - //--------------------------------------------------------------------- - // QRMaskPattern - //--------------------------------------------------------------------- - - var QRMaskPattern = { - PATTERN000 : 0, - PATTERN001 : 1, - PATTERN010 : 2, - PATTERN011 : 3, - PATTERN100 : 4, - PATTERN101 : 5, - PATTERN110 : 6, - PATTERN111 : 7 - }; - - //--------------------------------------------------------------------- - // QRUtil - //--------------------------------------------------------------------- - - var QRUtil = function() { - - var PATTERN_POSITION_TABLE = [ - [], - [6, 18], - [6, 22], - [6, 26], - [6, 30], - [6, 34], - [6, 22, 38], - [6, 24, 42], - [6, 26, 46], - [6, 28, 50], - [6, 30, 54], - [6, 32, 58], - [6, 34, 62], - [6, 26, 46, 66], - [6, 26, 48, 70], - [6, 26, 50, 74], - [6, 30, 54, 78], - [6, 30, 56, 82], - [6, 30, 58, 86], - [6, 34, 62, 90], - [6, 28, 50, 72, 94], - [6, 26, 50, 74, 98], - [6, 30, 54, 78, 102], - [6, 28, 54, 80, 106], - [6, 32, 58, 84, 110], - [6, 30, 58, 86, 114], - [6, 34, 62, 90, 118], - [6, 26, 50, 74, 98, 122], - [6, 30, 54, 78, 102, 126], - [6, 26, 52, 78, 104, 130], - [6, 30, 56, 82, 108, 134], - [6, 34, 60, 86, 112, 138], - [6, 30, 58, 86, 114, 142], - [6, 34, 62, 90, 118, 146], - [6, 30, 54, 78, 102, 126, 150], - [6, 24, 50, 76, 102, 128, 154], - [6, 28, 54, 80, 106, 132, 158], - [6, 32, 58, 84, 110, 136, 162], - [6, 26, 54, 82, 110, 138, 166], - [6, 30, 58, 86, 114, 142, 170] - ]; - var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); - var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); - var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); - - var _this = {}; - - var getBCHDigit = function(data) { - var digit = 0; - while (data != 0) { - digit += 1; - data >>>= 1; - } - return digit; - }; - - _this.getBCHTypeInfo = function(data) { - var d = data << 10; - while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { - d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); - } - return ( (data << 10) | d) ^ G15_MASK; - }; - - _this.getBCHTypeNumber = function(data) { - var d = data << 12; - while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { - d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); - } - return (data << 12) | d; - }; - - _this.getPatternPosition = function(typeNumber) { - return PATTERN_POSITION_TABLE[typeNumber - 1]; - }; - - _this.getMaskFunction = function(maskPattern) { - - switch (maskPattern) { - - case QRMaskPattern.PATTERN000 : - return function(i, j) { return (i + j) % 2 == 0; }; - case QRMaskPattern.PATTERN001 : - return function(i, j) { return i % 2 == 0; }; - case QRMaskPattern.PATTERN010 : - return function(i, j) { return j % 3 == 0; }; - case QRMaskPattern.PATTERN011 : - return function(i, j) { return (i + j) % 3 == 0; }; - case QRMaskPattern.PATTERN100 : - return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; }; - case QRMaskPattern.PATTERN101 : - return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; }; - case QRMaskPattern.PATTERN110 : - return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; }; - case QRMaskPattern.PATTERN111 : - return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; }; - - default : - throw new Error('bad maskPattern:' + maskPattern); - } - }; - - _this.getErrorCorrectPolynomial = function(errorCorrectLength) { - var a = qrPolynomial([1], 0); - for (var i = 0; i < errorCorrectLength; i += 1) { - a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) ); - } - return a; - }; - - _this.getLengthInBits = function(mode, type) { - - if (1 <= type && type < 10) { - - // 1 - 9 - - switch(mode) { - case QRMode.MODE_NUMBER : return 10; - case QRMode.MODE_ALPHA_NUM : return 9; - case QRMode.MODE_8BIT_BYTE : return 8; - case QRMode.MODE_KANJI : return 8; - default : - throw new Error('mode:' + mode); - } - - } else if (type < 27) { - - // 10 - 26 - - switch(mode) { - case QRMode.MODE_NUMBER : return 12; - case QRMode.MODE_ALPHA_NUM : return 11; - case QRMode.MODE_8BIT_BYTE : return 16; - case QRMode.MODE_KANJI : return 10; - default : - throw new Error('mode:' + mode); - } - - } else if (type < 41) { - - // 27 - 40 - - switch(mode) { - case QRMode.MODE_NUMBER : return 14; - case QRMode.MODE_ALPHA_NUM : return 13; - case QRMode.MODE_8BIT_BYTE : return 16; - case QRMode.MODE_KANJI : return 12; - default : - throw new Error('mode:' + mode); - } - - } else { - throw new Error('type:' + type); - } - }; - - _this.getLostPoint = function(qrcode) { - - var moduleCount = qrcode.getModuleCount(); - - var lostPoint = 0; - - // LEVEL1 - - for (var row = 0; row < moduleCount; row += 1) { - for (var col = 0; col < moduleCount; col += 1) { - - var sameCount = 0; - var dark = qrcode.isDark(row, col); - - for (var r = -1; r <= 1; r += 1) { - - if (row + r < 0 || moduleCount <= row + r) { - continue; - } - - for (var c = -1; c <= 1; c += 1) { - - if (col + c < 0 || moduleCount <= col + c) { - continue; - } - - if (r == 0 && c == 0) { - continue; - } - - if (dark == qrcode.isDark(row + r, col + c) ) { - sameCount += 1; - } - } - } - - if (sameCount > 5) { - lostPoint += (3 + sameCount - 5); - } - } - }; - - // LEVEL2 - - for (var row = 0; row < moduleCount - 1; row += 1) { - for (var col = 0; col < moduleCount - 1; col += 1) { - var count = 0; - if (qrcode.isDark(row, col) ) count += 1; - if (qrcode.isDark(row + 1, col) ) count += 1; - if (qrcode.isDark(row, col + 1) ) count += 1; - if (qrcode.isDark(row + 1, col + 1) ) count += 1; - if (count == 0 || count == 4) { - lostPoint += 3; - } - } - } - - // LEVEL3 - - for (var row = 0; row < moduleCount; row += 1) { - for (var col = 0; col < moduleCount - 6; col += 1) { - if (qrcode.isDark(row, col) - && !qrcode.isDark(row, col + 1) - && qrcode.isDark(row, col + 2) - && qrcode.isDark(row, col + 3) - && qrcode.isDark(row, col + 4) - && !qrcode.isDark(row, col + 5) - && qrcode.isDark(row, col + 6) ) { - lostPoint += 40; - } - } - } - - for (var col = 0; col < moduleCount; col += 1) { - for (var row = 0; row < moduleCount - 6; row += 1) { - if (qrcode.isDark(row, col) - && !qrcode.isDark(row + 1, col) - && qrcode.isDark(row + 2, col) - && qrcode.isDark(row + 3, col) - && qrcode.isDark(row + 4, col) - && !qrcode.isDark(row + 5, col) - && qrcode.isDark(row + 6, col) ) { - lostPoint += 40; - } - } - } - - // LEVEL4 - - var darkCount = 0; - - for (var col = 0; col < moduleCount; col += 1) { - for (var row = 0; row < moduleCount; row += 1) { - if (qrcode.isDark(row, col) ) { - darkCount += 1; - } - } - } - - var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; - lostPoint += ratio * 10; - - return lostPoint; - }; - - return _this; - }(); - - //--------------------------------------------------------------------- - // QRMath - //--------------------------------------------------------------------- - - var QRMath = function() { - - var EXP_TABLE = new Array(256); - var LOG_TABLE = new Array(256); - - // initialize tables - for (var i = 0; i < 8; i += 1) { - EXP_TABLE[i] = 1 << i; - } - for (var i = 8; i < 256; i += 1) { - EXP_TABLE[i] = EXP_TABLE[i - 4] - ^ EXP_TABLE[i - 5] - ^ EXP_TABLE[i - 6] - ^ EXP_TABLE[i - 8]; - } - for (var i = 0; i < 255; i += 1) { - LOG_TABLE[EXP_TABLE[i] ] = i; - } - - var _this = {}; - - _this.glog = function(n) { - - if (n < 1) { - throw new Error('glog(' + n + ')'); - } - - return LOG_TABLE[n]; - }; - - _this.gexp = function(n) { - - while (n < 0) { - n += 255; - } - - while (n >= 256) { - n -= 255; - } - - return EXP_TABLE[n]; - }; - - return _this; - }(); - - //--------------------------------------------------------------------- - // qrPolynomial - //--------------------------------------------------------------------- - - function qrPolynomial(num, shift) { - - if (typeof num.length == 'undefined') { - throw new Error(num.length + '/' + shift); - } - - var _num = function() { - var offset = 0; - while (offset < num.length && num[offset] == 0) { - offset += 1; - } - var _num = new Array(num.length - offset + shift); - for (var i = 0; i < num.length - offset; i += 1) { - _num[i] = num[i + offset]; - } - return _num; - }(); - - var _this = {}; - - _this.getAt = function(index) { - return _num[index]; - }; - - _this.getLength = function() { - return _num.length; - }; - - _this.multiply = function(e) { - - var num = new Array(_this.getLength() + e.getLength() - 1); - - for (var i = 0; i < _this.getLength(); i += 1) { - for (var j = 0; j < e.getLength(); j += 1) { - num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) ); - } - } - - return qrPolynomial(num, 0); - }; - - _this.mod = function(e) { - - if (_this.getLength() - e.getLength() < 0) { - return _this; - } - - var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) ); - - var num = new Array(_this.getLength() ); - for (var i = 0; i < _this.getLength(); i += 1) { - num[i] = _this.getAt(i); - } - - for (var i = 0; i < e.getLength(); i += 1) { - num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); - } - - // recursive call - return qrPolynomial(num, 0).mod(e); - }; - - return _this; - }; - - //--------------------------------------------------------------------- - // QRRSBlock - //--------------------------------------------------------------------- - - var QRRSBlock = function() { - - var RS_BLOCK_TABLE = [ - - // L - // M - // Q - // H - - // 1 - [1, 26, 19], - [1, 26, 16], - [1, 26, 13], - [1, 26, 9], - - // 2 - [1, 44, 34], - [1, 44, 28], - [1, 44, 22], - [1, 44, 16], - - // 3 - [1, 70, 55], - [1, 70, 44], - [2, 35, 17], - [2, 35, 13], - - // 4 - [1, 100, 80], - [2, 50, 32], - [2, 50, 24], - [4, 25, 9], - - // 5 - [1, 134, 108], - [2, 67, 43], - [2, 33, 15, 2, 34, 16], - [2, 33, 11, 2, 34, 12], - - // 6 - [2, 86, 68], - [4, 43, 27], - [4, 43, 19], - [4, 43, 15], - - // 7 - [2, 98, 78], - [4, 49, 31], - [2, 32, 14, 4, 33, 15], - [4, 39, 13, 1, 40, 14], - - // 8 - [2, 121, 97], - [2, 60, 38, 2, 61, 39], - [4, 40, 18, 2, 41, 19], - [4, 40, 14, 2, 41, 15], - - // 9 - [2, 146, 116], - [3, 58, 36, 2, 59, 37], - [4, 36, 16, 4, 37, 17], - [4, 36, 12, 4, 37, 13], - - // 10 - [2, 86, 68, 2, 87, 69], - [4, 69, 43, 1, 70, 44], - [6, 43, 19, 2, 44, 20], - [6, 43, 15, 2, 44, 16], - - // 11 - [4, 101, 81], - [1, 80, 50, 4, 81, 51], - [4, 50, 22, 4, 51, 23], - [3, 36, 12, 8, 37, 13], - - // 12 - [2, 116, 92, 2, 117, 93], - [6, 58, 36, 2, 59, 37], - [4, 46, 20, 6, 47, 21], - [7, 42, 14, 4, 43, 15], - - // 13 - [4, 133, 107], - [8, 59, 37, 1, 60, 38], - [8, 44, 20, 4, 45, 21], - [12, 33, 11, 4, 34, 12], - - // 14 - [3, 145, 115, 1, 146, 116], - [4, 64, 40, 5, 65, 41], - [11, 36, 16, 5, 37, 17], - [11, 36, 12, 5, 37, 13], - - // 15 - [5, 109, 87, 1, 110, 88], - [5, 65, 41, 5, 66, 42], - [5, 54, 24, 7, 55, 25], - [11, 36, 12, 7, 37, 13], - - // 16 - [5, 122, 98, 1, 123, 99], - [7, 73, 45, 3, 74, 46], - [15, 43, 19, 2, 44, 20], - [3, 45, 15, 13, 46, 16], - - // 17 - [1, 135, 107, 5, 136, 108], - [10, 74, 46, 1, 75, 47], - [1, 50, 22, 15, 51, 23], - [2, 42, 14, 17, 43, 15], - - // 18 - [5, 150, 120, 1, 151, 121], - [9, 69, 43, 4, 70, 44], - [17, 50, 22, 1, 51, 23], - [2, 42, 14, 19, 43, 15], - - // 19 - [3, 141, 113, 4, 142, 114], - [3, 70, 44, 11, 71, 45], - [17, 47, 21, 4, 48, 22], - [9, 39, 13, 16, 40, 14], - - // 20 - [3, 135, 107, 5, 136, 108], - [3, 67, 41, 13, 68, 42], - [15, 54, 24, 5, 55, 25], - [15, 43, 15, 10, 44, 16], - - // 21 - [4, 144, 116, 4, 145, 117], - [17, 68, 42], - [17, 50, 22, 6, 51, 23], - [19, 46, 16, 6, 47, 17], - - // 22 - [2, 139, 111, 7, 140, 112], - [17, 74, 46], - [7, 54, 24, 16, 55, 25], - [34, 37, 13], - - // 23 - [4, 151, 121, 5, 152, 122], - [4, 75, 47, 14, 76, 48], - [11, 54, 24, 14, 55, 25], - [16, 45, 15, 14, 46, 16], - - // 24 - [6, 147, 117, 4, 148, 118], - [6, 73, 45, 14, 74, 46], - [11, 54, 24, 16, 55, 25], - [30, 46, 16, 2, 47, 17], - - // 25 - [8, 132, 106, 4, 133, 107], - [8, 75, 47, 13, 76, 48], - [7, 54, 24, 22, 55, 25], - [22, 45, 15, 13, 46, 16], - - // 26 - [10, 142, 114, 2, 143, 115], - [19, 74, 46, 4, 75, 47], - [28, 50, 22, 6, 51, 23], - [33, 46, 16, 4, 47, 17], - - // 27 - [8, 152, 122, 4, 153, 123], - [22, 73, 45, 3, 74, 46], - [8, 53, 23, 26, 54, 24], - [12, 45, 15, 28, 46, 16], - - // 28 - [3, 147, 117, 10, 148, 118], - [3, 73, 45, 23, 74, 46], - [4, 54, 24, 31, 55, 25], - [11, 45, 15, 31, 46, 16], - - // 29 - [7, 146, 116, 7, 147, 117], - [21, 73, 45, 7, 74, 46], - [1, 53, 23, 37, 54, 24], - [19, 45, 15, 26, 46, 16], - - // 30 - [5, 145, 115, 10, 146, 116], - [19, 75, 47, 10, 76, 48], - [15, 54, 24, 25, 55, 25], - [23, 45, 15, 25, 46, 16], - - // 31 - [13, 145, 115, 3, 146, 116], - [2, 74, 46, 29, 75, 47], - [42, 54, 24, 1, 55, 25], - [23, 45, 15, 28, 46, 16], - - // 32 - [17, 145, 115], - [10, 74, 46, 23, 75, 47], - [10, 54, 24, 35, 55, 25], - [19, 45, 15, 35, 46, 16], - - // 33 - [17, 145, 115, 1, 146, 116], - [14, 74, 46, 21, 75, 47], - [29, 54, 24, 19, 55, 25], - [11, 45, 15, 46, 46, 16], - - // 34 - [13, 145, 115, 6, 146, 116], - [14, 74, 46, 23, 75, 47], - [44, 54, 24, 7, 55, 25], - [59, 46, 16, 1, 47, 17], - - // 35 - [12, 151, 121, 7, 152, 122], - [12, 75, 47, 26, 76, 48], - [39, 54, 24, 14, 55, 25], - [22, 45, 15, 41, 46, 16], - - // 36 - [6, 151, 121, 14, 152, 122], - [6, 75, 47, 34, 76, 48], - [46, 54, 24, 10, 55, 25], - [2, 45, 15, 64, 46, 16], - - // 37 - [17, 152, 122, 4, 153, 123], - [29, 74, 46, 14, 75, 47], - [49, 54, 24, 10, 55, 25], - [24, 45, 15, 46, 46, 16], - - // 38 - [4, 152, 122, 18, 153, 123], - [13, 74, 46, 32, 75, 47], - [48, 54, 24, 14, 55, 25], - [42, 45, 15, 32, 46, 16], - - // 39 - [20, 147, 117, 4, 148, 118], - [40, 75, 47, 7, 76, 48], - [43, 54, 24, 22, 55, 25], - [10, 45, 15, 67, 46, 16], - - // 40 - [19, 148, 118, 6, 149, 119], - [18, 75, 47, 31, 76, 48], - [34, 54, 24, 34, 55, 25], - [20, 45, 15, 61, 46, 16] - ]; - - var qrRSBlock = function(totalCount, dataCount) { - var _this = {}; - _this.totalCount = totalCount; - _this.dataCount = dataCount; - return _this; - }; - - var _this = {}; - - var getRsBlockTable = function(typeNumber, errorCorrectLevel) { - - switch(errorCorrectLevel) { - case QRErrorCorrectLevel.L : - return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; - case QRErrorCorrectLevel.M : - return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; - case QRErrorCorrectLevel.Q : - return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; - case QRErrorCorrectLevel.H : - return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; - default : - return undefined; - } - }; - - _this.getRSBlocks = function(typeNumber, errorCorrectLevel) { - - var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel); - - if (typeof rsBlock == 'undefined') { - throw new Error('bad rs block @ typeNumber:' + typeNumber + - '/errorCorrectLevel:' + errorCorrectLevel); - } - - var length = rsBlock.length / 3; - - var list = new Array(); - - for (var i = 0; i < length; i += 1) { - - var count = rsBlock[i * 3 + 0]; - var totalCount = rsBlock[i * 3 + 1]; - var dataCount = rsBlock[i * 3 + 2]; - - for (var j = 0; j < count; j += 1) { - list.push(qrRSBlock(totalCount, dataCount) ); - } - } - - return list; - }; - - return _this; - }(); - - //--------------------------------------------------------------------- - // qrBitBuffer - //--------------------------------------------------------------------- - - var qrBitBuffer = function() { - - var _buffer = new Array(); - var _length = 0; - - var _this = {}; - - _this.getBuffer = function() { - return _buffer; - }; - - _this.getAt = function(index) { - var bufIndex = Math.floor(index / 8); - return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1; - }; - - _this.put = function(num, length) { - for (var i = 0; i < length; i += 1) { - _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); - } - }; - - _this.getLengthInBits = function() { - return _length; - }; - - _this.putBit = function(bit) { - - var bufIndex = Math.floor(_length / 8); - if (_buffer.length <= bufIndex) { - _buffer.push(0); - } - - if (bit) { - _buffer[bufIndex] |= (0x80 >>> (_length % 8) ); - } - - _length += 1; - }; - - return _this; - }; - - //--------------------------------------------------------------------- - // qr8BitByte - //--------------------------------------------------------------------- - - var qr8BitByte = function(data) { - - var _mode = QRMode.MODE_8BIT_BYTE; - var _data = data; - var _bytes = qrcode.stringToBytes(data); - - var _this = {}; - - _this.getMode = function() { - return _mode; - }; - - _this.getLength = function(buffer) { - return _bytes.length; - }; - - _this.write = function(buffer) { - for (var i = 0; i < _bytes.length; i += 1) { - buffer.put(_bytes[i], 8); - } - }; - - return _this; - }; - - //===================================================================== - // GIF Support etc. - // - - //--------------------------------------------------------------------- - // byteArrayOutputStream - //--------------------------------------------------------------------- - - var byteArrayOutputStream = function() { - - var _bytes = new Array(); - - var _this = {}; - - _this.writeByte = function(b) { - _bytes.push(b & 0xff); - }; - - _this.writeShort = function(i) { - _this.writeByte(i); - _this.writeByte(i >>> 8); - }; - - _this.writeBytes = function(b, off, len) { - off = off || 0; - len = len || b.length; - for (var i = 0; i < len; i += 1) { - _this.writeByte(b[i + off]); - } - }; - - _this.writeString = function(s) { - for (var i = 0; i < s.length; i += 1) { - _this.writeByte(s.charCodeAt(i) ); - } - }; - - _this.toByteArray = function() { - return _bytes; - }; - - _this.toString = function() { - var s = ''; - s += '['; - for (var i = 0; i < _bytes.length; i += 1) { - if (i > 0) { - s += ','; - } - s += _bytes[i]; - } - s += ']'; - return s; - }; - - return _this; - }; - - //--------------------------------------------------------------------- - // base64EncodeOutputStream - //--------------------------------------------------------------------- - - var base64EncodeOutputStream = function() { - - var _buffer = 0; - var _buflen = 0; - var _length = 0; - var _base64 = ''; - - var _this = {}; - - var writeEncoded = function(b) { - _base64 += String.fromCharCode(encode(b & 0x3f) ); - }; - - var encode = function(n) { - if (n < 0) { - // error. - } else if (n < 26) { - return 0x41 + n; - } else if (n < 52) { - return 0x61 + (n - 26); - } else if (n < 62) { - return 0x30 + (n - 52); - } else if (n == 62) { - return 0x2b; - } else if (n == 63) { - return 0x2f; - } - throw new Error('n:' + n); - }; - - _this.writeByte = function(n) { - - _buffer = (_buffer << 8) | (n & 0xff); - _buflen += 8; - _length += 1; - - while (_buflen >= 6) { - writeEncoded(_buffer >>> (_buflen - 6) ); - _buflen -= 6; - } - }; - - _this.flush = function() { - - if (_buflen > 0) { - writeEncoded(_buffer << (6 - _buflen) ); - _buffer = 0; - _buflen = 0; - } - - if (_length % 3 != 0) { - // padding - var padlen = 3 - _length % 3; - for (var i = 0; i < padlen; i += 1) { - _base64 += '='; - } - } - }; - - _this.toString = function() { - return _base64; - }; - - return _this; - }; - - //--------------------------------------------------------------------- - // base64DecodeInputStream - //--------------------------------------------------------------------- - - var base64DecodeInputStream = function(str) { - - var _str = str; - var _pos = 0; - var _buffer = 0; - var _buflen = 0; - - var _this = {}; - - _this.read = function() { - - while (_buflen < 8) { - - if (_pos >= _str.length) { - if (_buflen == 0) { - return -1; - } - throw new Error('unexpected end of file./' + _buflen); - } - - var c = _str.charAt(_pos); - _pos += 1; - - if (c == '=') { - _buflen = 0; - return -1; - } else if (c.match(/^\s$/) ) { - // ignore if whitespace. - continue; - } - - _buffer = (_buffer << 6) | decode(c.charCodeAt(0) ); - _buflen += 6; - } - - var n = (_buffer >>> (_buflen - 8) ) & 0xff; - _buflen -= 8; - return n; - }; - - var decode = function(c) { - if (0x41 <= c && c <= 0x5a) { - return c - 0x41; - } else if (0x61 <= c && c <= 0x7a) { - return c - 0x61 + 26; - } else if (0x30 <= c && c <= 0x39) { - return c - 0x30 + 52; - } else if (c == 0x2b) { - return 62; - } else if (c == 0x2f) { - return 63; - } else { - throw new Error('c:' + c); - } - }; - - return _this; - }; - - //--------------------------------------------------------------------- - // gifImage (B/W) - //--------------------------------------------------------------------- - - var gifImage = function(width, height) { - - var _width = width; - var _height = height; - var _data = new Array(width * height); - - var _this = {}; - - _this.setPixel = function(x, y, pixel) { - _data[y * _width + x] = pixel; - }; - - _this.write = function(out) { - - //--------------------------------- - // GIF Signature - - out.writeString('GIF87a'); - - //--------------------------------- - // Screen Descriptor - - out.writeShort(_width); - out.writeShort(_height); - - out.writeByte(0x80); // 2bit - out.writeByte(0); - out.writeByte(0); - - //--------------------------------- - // Global Color Map - - // black - out.writeByte(0x00); - out.writeByte(0x00); - out.writeByte(0x00); - - // white - out.writeByte(0xff); - out.writeByte(0xff); - out.writeByte(0xff); - - //--------------------------------- - // Image Descriptor - - out.writeString(','); - out.writeShort(0); - out.writeShort(0); - out.writeShort(_width); - out.writeShort(_height); - out.writeByte(0); - - //--------------------------------- - // Local Color Map - - //--------------------------------- - // Raster Data - - var lzwMinCodeSize = 2; - var raster = getLZWRaster(lzwMinCodeSize); - - out.writeByte(lzwMinCodeSize); - - var offset = 0; - - while (raster.length - offset > 255) { - out.writeByte(255); - out.writeBytes(raster, offset, 255); - offset += 255; - } - - out.writeByte(raster.length - offset); - out.writeBytes(raster, offset, raster.length - offset); - out.writeByte(0x00); - - //--------------------------------- - // GIF Terminator - out.writeString(';'); - }; - - var bitOutputStream = function(out) { - - var _out = out; - var _bitLength = 0; - var _bitBuffer = 0; - - var _this = {}; - - _this.write = function(data, length) { - - if ( (data >>> length) != 0) { - throw new Error('length over'); - } - - while (_bitLength + length >= 8) { - _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) ); - length -= (8 - _bitLength); - data >>>= (8 - _bitLength); - _bitBuffer = 0; - _bitLength = 0; - } - - _bitBuffer = (data << _bitLength) | _bitBuffer; - _bitLength = _bitLength + length; - }; - - _this.flush = function() { - if (_bitLength > 0) { - _out.writeByte(_bitBuffer); - } - }; - - return _this; - }; - - var getLZWRaster = function(lzwMinCodeSize) { - - var clearCode = 1 << lzwMinCodeSize; - var endCode = (1 << lzwMinCodeSize) + 1; - var bitLength = lzwMinCodeSize + 1; - - // Setup LZWTable - var table = lzwTable(); - - for (var i = 0; i < clearCode; i += 1) { - table.add(String.fromCharCode(i) ); - } - table.add(String.fromCharCode(clearCode) ); - table.add(String.fromCharCode(endCode) ); - - var byteOut = byteArrayOutputStream(); - var bitOut = bitOutputStream(byteOut); - - // clear code - bitOut.write(clearCode, bitLength); - - var dataIndex = 0; - - var s = String.fromCharCode(_data[dataIndex]); - dataIndex += 1; - - while (dataIndex < _data.length) { - - var c = String.fromCharCode(_data[dataIndex]); - dataIndex += 1; - - if (table.contains(s + c) ) { - - s = s + c; - - } else { - - bitOut.write(table.indexOf(s), bitLength); - - if (table.size() < 0xfff) { - - if (table.size() == (1 << bitLength) ) { - bitLength += 1; - } - - table.add(s + c); - } - - s = c; - } - } - - bitOut.write(table.indexOf(s), bitLength); - - // end code - bitOut.write(endCode, bitLength); - - bitOut.flush(); - - return byteOut.toByteArray(); - }; - - var lzwTable = function() { - - var _map = {}; - var _size = 0; - - var _this = {}; - - _this.add = function(key) { - if (_this.contains(key) ) { - throw new Error('dup key:' + key); - } - _map[key] = _size; - _size += 1; - }; - - _this.size = function() { - return _size; - }; - - _this.indexOf = function(key) { - return _map[key]; - }; - - _this.contains = function(key) { - return typeof _map[key] != 'undefined'; - }; - - return _this; - }; - - return _this; - }; - - var createImgTag = function(width, height, getPixel, alt) { - - var gif = gifImage(width, height); - for (var y = 0; y < height; y += 1) { - for (var x = 0; x < width; x += 1) { - gif.setPixel(x, y, getPixel(x, y) ); - } - } - - var b = byteArrayOutputStream(); - gif.write(b); - - var base64 = base64EncodeOutputStream(); - var bytes = b.toByteArray(); - for (var i = 0; i < bytes.length; i += 1) { - base64.writeByte(bytes[i]); - } - base64.flush(); - - var img = ''; - img += ' width || y < - 1 || y > height) - { - throw "Error.checkAndNudgePoints "; - } - nudged = false; - if (x == - 1) - { - points[offset] = 0.0; - nudged = true; - } - else if (x == width) - { - points[offset] = width - 1; - nudged = true; - } - if (y == - 1) - { - points[offset + 1] = 0.0; - nudged = true; - } - else if (y == height) - { - points[offset + 1] = height - 1; - nudged = true; - } - } - // Check and nudge points from end: - nudged = true; - for (var offset = points.length - 2; offset >= 0 && nudged; offset -= 2) - { - var x = Math.floor( points[offset]); - var y = Math.floor( points[offset + 1]); - if (x < - 1 || x > width || y < - 1 || y > height) - { - throw "Error.checkAndNudgePoints "; - } - nudged = false; - if (x == - 1) - { - points[offset] = 0.0; - nudged = true; - } - else if (x == width) - { - points[offset] = width - 1; - nudged = true; - } - if (y == - 1) - { - points[offset + 1] = 0.0; - nudged = true; - } - else if (y == height) - { - points[offset + 1] = height - 1; - nudged = true; - } - } - } - - - -GridSampler.sampleGrid3=function( image, dimension, transform) - { - var bits = new BitMatrix(dimension); - var points = new Array(dimension << 1); - for (var y = 0; y < dimension; y++) - { - var max = points.length; - var iValue = y + 0.5; - for (var x = 0; x < max; x += 2) - { - points[x] = (x >> 1) + 0.5; - points[x + 1] = iValue; - } - transform.transformPoints1(points); - // Quick check to see if points transformed to something inside the image; - // sufficient to check the endpoints - GridSampler.checkAndNudgePoints(image, points); - try - { - for (var x = 0; x < max; x += 2) - { - var xpoint = (Math.floor( points[x]) * 4) + (Math.floor( points[x + 1]) * qrcode.width * 4); - var bit = image[Math.floor( points[x])+ qrcode.width* Math.floor( points[x + 1])]; - qrcode.imagedata.data[xpoint] = bit?255:0; - qrcode.imagedata.data[xpoint+1] = bit?255:0; - qrcode.imagedata.data[xpoint+2] = 0; - qrcode.imagedata.data[xpoint+3] = 255; - //bits[x >> 1][ y]=bit; - if(bit) - bits.set_Renamed(x >> 1, y); - } - } - catch ( aioobe) - { - // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting - // transform gets "twisted" such that it maps a straight line of points to a set of points - // whose endpoints are in bounds, but others are not. There is probably some mathematical - // way to detect this about the transformation that I don't know yet. - // This results in an ugly runtime exception despite our clever checks above -- can't have - // that. We could check each point's coordinates but that feels duplicative. We settle for - // catching and wrapping ArrayIndexOutOfBoundsException. - throw "Error.checkAndNudgePoints"; - } - } - return bits; - } - -GridSampler.sampleGridx=function( image, dimension, p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY) -{ - var transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); - - return GridSampler.sampleGrid3(image, dimension, transform); -} - -// Source: src/version.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - - -function ECB(count, dataCodewords) -{ - this.count = count; - this.dataCodewords = dataCodewords; - - this.__defineGetter__("Count", function() - { - return this.count; - }); - this.__defineGetter__("DataCodewords", function() - { - return this.dataCodewords; - }); -} - -function ECBlocks( ecCodewordsPerBlock, ecBlocks1, ecBlocks2) -{ - this.ecCodewordsPerBlock = ecCodewordsPerBlock; - if(ecBlocks2) - this.ecBlocks = new Array(ecBlocks1, ecBlocks2); - else - this.ecBlocks = new Array(ecBlocks1); - - this.__defineGetter__("ECCodewordsPerBlock", function() - { - return this.ecCodewordsPerBlock; - }); - - this.__defineGetter__("TotalECCodewords", function() - { - return this.ecCodewordsPerBlock * this.NumBlocks; - }); - - this.__defineGetter__("NumBlocks", function() - { - var total = 0; - for (var i = 0; i < this.ecBlocks.length; i++) - { - total += this.ecBlocks[i].length; - } - return total; - }); - - this.getECBlocks=function() - { - return this.ecBlocks; - } -} - -function Version( versionNumber, alignmentPatternCenters, ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4) -{ - this.versionNumber = versionNumber; - this.alignmentPatternCenters = alignmentPatternCenters; - this.ecBlocks = new Array(ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4); - - var total = 0; - var ecCodewords = ecBlocks1.ECCodewordsPerBlock; - var ecbArray = ecBlocks1.getECBlocks(); - for (var i = 0; i < ecbArray.length; i++) - { - var ecBlock = ecbArray[i]; - total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); - } - this.totalCodewords = total; - - this.__defineGetter__("VersionNumber", function() - { - return this.versionNumber; - }); - - this.__defineGetter__("AlignmentPatternCenters", function() - { - return this.alignmentPatternCenters; - }); - this.__defineGetter__("TotalCodewords", function() - { - return this.totalCodewords; - }); - this.__defineGetter__("DimensionForVersion", function() - { - return 17 + 4 * this.versionNumber; - }); - - this.buildFunctionPattern=function() - { - var dimension = this.DimensionForVersion; - var bitMatrix = new BitMatrix(dimension); - - // Top left finder pattern + separator + format - bitMatrix.setRegion(0, 0, 9, 9); - // Top right finder pattern + separator + format - bitMatrix.setRegion(dimension - 8, 0, 8, 9); - // Bottom left finder pattern + separator + format - bitMatrix.setRegion(0, dimension - 8, 9, 8); - - // Alignment patterns - var max = this.alignmentPatternCenters.length; - for (var x = 0; x < max; x++) - { - var i = this.alignmentPatternCenters[x] - 2; - for (var y = 0; y < max; y++) - { - if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) - { - // No alignment patterns near the three finder paterns - continue; - } - bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5); - } - } - - // Vertical timing pattern - bitMatrix.setRegion(6, 9, 1, dimension - 17); - // Horizontal timing pattern - bitMatrix.setRegion(9, 6, dimension - 17, 1); - - if (this.versionNumber > 6) - { - // Version info, top right - bitMatrix.setRegion(dimension - 11, 0, 3, 6); - // Version info, bottom left - bitMatrix.setRegion(0, dimension - 11, 6, 3); - } - - return bitMatrix; - } - this.getECBlocksForLevel=function( ecLevel) - { - return this.ecBlocks[ecLevel.ordinal()]; - } -} - -Version.VERSION_DECODE_INFO = new Array(0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69); - -Version.VERSIONS = buildVersions(); - -Version.getVersionForNumber=function( versionNumber) -{ - if (versionNumber < 1 || versionNumber > 40) - { - throw "ArgumentException"; - } - return Version.VERSIONS[versionNumber - 1]; -} - -Version.getProvisionalVersionForDimension=function(dimension) -{ - if (dimension % 4 != 1) - { - throw "Error getProvisionalVersionForDimension"; - } - try - { - return Version.getVersionForNumber((dimension - 17) >> 2); - } - catch ( iae) - { - throw "Error getVersionForNumber"; - } -} - -Version.decodeVersionInformation=function( versionBits) -{ - var bestDifference = 0xffffffff; - var bestVersion = 0; - for (var i = 0; i < Version.VERSION_DECODE_INFO.length; i++) - { - var targetVersion = Version.VERSION_DECODE_INFO[i]; - // Do the version info bits match exactly? done. - if (targetVersion == versionBits) - { - return this.getVersionForNumber(i + 7); - } - // Otherwise see if this is the closest to a real version info bit string - // we have seen so far - var bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); - if (bitsDifference < bestDifference) - { - bestVersion = i + 7; - bestDifference = bitsDifference; - } - } - // We can tolerate up to 3 bits of error since no two version info codewords will - // differ in less than 4 bits. - if (bestDifference <= 3) - { - return this.getVersionForNumber(bestVersion); - } - // If we didn't find a close enough match, fail - return null; -} - -function buildVersions() -{ - return new Array(new Version(1, new Array(), new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))), - new Version(2, new Array(6, 18), new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))), - new Version(3, new Array(6, 22), new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))), - new Version(4, new Array(6, 26), new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))), - new Version(5, new Array(6, 30), new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))), - new Version(6, new Array(6, 34), new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))), - new Version(7, new Array(6, 22, 38), new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))), - new Version(8, new Array(6, 24, 42), new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))), - new Version(9, new Array(6, 26, 46), new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))), - new Version(10, new Array(6, 28, 50), new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))), - new Version(11, new Array(6, 30, 54), new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))), - new Version(12, new Array(6, 32, 58), new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))), - new Version(13, new Array(6, 34, 62), new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))), - new Version(14, new Array(6, 26, 46, 66), new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))), - new Version(15, new Array(6, 26, 48, 70), new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))), - new Version(16, new Array(6, 26, 50, 74), new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))), - new Version(17, new Array(6, 30, 54, 78), new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))), - new Version(18, new Array(6, 30, 56, 82), new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))), - new Version(19, new Array(6, 30, 58, 86), new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))), - new Version(20, new Array(6, 34, 62, 90), new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))), - new Version(21, new Array(6, 28, 50, 72, 94), new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))), - new Version(22, new Array(6, 26, 50, 74, 98), new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))), - new Version(23, new Array(6, 30, 54, 74, 102), new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))), - new Version(24, new Array(6, 28, 54, 80, 106), new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))), - new Version(25, new Array(6, 32, 58, 84, 110), new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))), - new Version(26, new Array(6, 30, 58, 86, 114), new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))), - new Version(27, new Array(6, 34, 62, 90, 118), new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))), - new Version(28, new Array(6, 26, 50, 74, 98, 122), new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))), - new Version(29, new Array(6, 30, 54, 78, 102, 126), new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))), - new Version(30, new Array(6, 26, 52, 78, 104, 130), new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))), - new Version(31, new Array(6, 30, 56, 82, 108, 134), new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))), - new Version(32, new Array(6, 34, 60, 86, 112, 138), new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))), - new Version(33, new Array(6, 30, 58, 86, 114, 142), new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))), - new Version(34, new Array(6, 34, 62, 90, 118, 146), new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))), - new Version(35, new Array(6, 30, 54, 78, 102, 126, 150), new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)),new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))), - new Version(36, new Array(6, 24, 50, 76, 102, 128, 154), new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))), - new Version(37, new Array(6, 28, 54, 80, 106, 132, 158), new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))), - new Version(38, new Array(6, 32, 58, 84, 110, 136, 162), new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))), - new Version(39, new Array(6, 26, 54, 82, 110, 138, 166), new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))), - new Version(40, new Array(6, 30, 58, 86, 114, 142, 170), new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16)))); -} -// Source: src/detector.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function PerspectiveTransform( a11, a21, a31, a12, a22, a32, a13, a23, a33) -{ - this.a11 = a11; - this.a12 = a12; - this.a13 = a13; - this.a21 = a21; - this.a22 = a22; - this.a23 = a23; - this.a31 = a31; - this.a32 = a32; - this.a33 = a33; - this.transformPoints1=function( points) - { - var max = points.length; - var a11 = this.a11; - var a12 = this.a12; - var a13 = this.a13; - var a21 = this.a21; - var a22 = this.a22; - var a23 = this.a23; - var a31 = this.a31; - var a32 = this.a32; - var a33 = this.a33; - for (var i = 0; i < max; i += 2) - { - var x = points[i]; - var y = points[i + 1]; - var denominator = a13 * x + a23 * y + a33; - points[i] = (a11 * x + a21 * y + a31) / denominator; - points[i + 1] = (a12 * x + a22 * y + a32) / denominator; - } - } - this. transformPoints2=function(xValues, yValues) - { - var n = xValues.length; - for (var i = 0; i < n; i++) - { - var x = xValues[i]; - var y = yValues[i]; - var denominator = this.a13 * x + this.a23 * y + this.a33; - xValues[i] = (this.a11 * x + this.a21 * y + this.a31) / denominator; - yValues[i] = (this.a12 * x + this.a22 * y + this.a32) / denominator; - } - } - - this.buildAdjoint=function() - { - // Adjoint is the transpose of the cofactor matrix: - return new PerspectiveTransform(this.a22 * this.a33 - this.a23 * this.a32, this.a23 * this.a31 - this.a21 * this.a33, this.a21 * this.a32 - this.a22 * this.a31, this.a13 * this.a32 - this.a12 * this.a33, this.a11 * this.a33 - this.a13 * this.a31, this.a12 * this.a31 - this.a11 * this.a32, this.a12 * this.a23 - this.a13 * this.a22, this.a13 * this.a21 - this.a11 * this.a23, this.a11 * this.a22 - this.a12 * this.a21); - } - this.times=function( other) - { - return new PerspectiveTransform(this.a11 * other.a11 + this.a21 * other.a12 + this.a31 * other.a13, this.a11 * other.a21 + this.a21 * other.a22 + this.a31 * other.a23, this.a11 * other.a31 + this.a21 * other.a32 + this.a31 * other.a33, this.a12 * other.a11 + this.a22 * other.a12 + this.a32 * other.a13, this.a12 * other.a21 + this.a22 * other.a22 + this.a32 * other.a23, this.a12 * other.a31 + this.a22 * other.a32 + this.a32 * other.a33, this.a13 * other.a11 + this.a23 * other.a12 +this.a33 * other.a13, this.a13 * other.a21 + this.a23 * other.a22 + this.a33 * other.a23, this.a13 * other.a31 + this.a23 * other.a32 + this.a33 * other.a33); - } - -} - -PerspectiveTransform.quadrilateralToQuadrilateral=function( x0, y0, x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p) -{ - - var qToS = this.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); - var sToQ = this.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); - return sToQ.times(qToS); -} - -PerspectiveTransform.squareToQuadrilateral=function( x0, y0, x1, y1, x2, y2, x3, y3) -{ - dy2 = y3 - y2; - dy3 = y0 - y1 + y2 - y3; - if (dy2 == 0.0 && dy3 == 0.0) - { - return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0, 0.0, 1.0); - } - else - { - dx1 = x1 - x2; - dx2 = x3 - x2; - dx3 = x0 - x1 + x2 - x3; - dy1 = y1 - y2; - denominator = dx1 * dy2 - dx2 * dy1; - a13 = (dx3 * dy2 - dx2 * dy3) / denominator; - a23 = (dx1 * dy3 - dx3 * dy1) / denominator; - return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0); - } -} - -PerspectiveTransform.quadrilateralToSquare=function( x0, y0, x1, y1, x2, y2, x3, y3) -{ - // Here, the adjoint serves as the inverse: - return this.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint(); -} - -function DetectorResult(bits, points) -{ - this.bits = bits; - this.points = points; -} - - -function Detector(image) -{ - this.image=image; - this.resultPointCallback = null; - - this.sizeOfBlackWhiteBlackRun=function( fromX, fromY, toX, toY) - { - // Mild variant of Bresenham's algorithm; - // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm - var steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); - if (steep) - { - var temp = fromX; - fromX = fromY; - fromY = temp; - temp = toX; - toX = toY; - toY = temp; - } - - var dx = Math.abs(toX - fromX); - var dy = Math.abs(toY - fromY); - var error = - dx >> 1; - var ystep = fromY < toY?1:- 1; - var xstep = fromX < toX?1:- 1; - var state = 0; // In black pixels, looking for white, first or second time - for (var x = fromX, y = fromY; x != toX; x += xstep) - { - - var realX = steep?y:x; - var realY = steep?x:y; - if (state == 1) - { - // In white pixels, looking for black - if (this.image[realX + realY*qrcode.width]) - { - state++; - } - } - else - { - if (!this.image[realX + realY*qrcode.width]) - { - state++; - } - } - - if (state == 3) - { - // Found black, white, black, and stumbled back onto white; done - var diffX = x - fromX; - var diffY = y - fromY; - return Math.sqrt( (diffX * diffX + diffY * diffY)); - } - error += dy; - if (error > 0) - { - if (y == toY) - { - break; - } - y += ystep; - error -= dx; - } - } - var diffX2 = toX - fromX; - var diffY2 = toY - fromY; - return Math.sqrt( (diffX2 * diffX2 + diffY2 * diffY2)); - } - - - this.sizeOfBlackWhiteBlackRunBothWays=function( fromX, fromY, toX, toY) - { - - var result = this.sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY); - - // Now count other way -- don't run off image though of course - var scale = 1.0; - var otherToX = fromX - (toX - fromX); - if (otherToX < 0) - { - scale = fromX / (fromX - otherToX); - otherToX = 0; - } - else if (otherToX >= qrcode.width) - { - scale = (qrcode.width - 1 - fromX) / (otherToX - fromX); - otherToX = qrcode.width - 1; - } - var otherToY = Math.floor (fromY - (toY - fromY) * scale); - - scale = 1.0; - if (otherToY < 0) - { - scale = fromY / (fromY - otherToY); - otherToY = 0; - } - else if (otherToY >= qrcode.height) - { - scale = (qrcode.height - 1 - fromY) / (otherToY - fromY); - otherToY = qrcode.height - 1; - } - otherToX = Math.floor (fromX + (otherToX - fromX) * scale); - - result += this.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); - return result - 1.0; // -1 because we counted the middle pixel twice - } - - - - this.calculateModuleSizeOneWay=function( pattern, otherPattern) - { - var moduleSizeEst1 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor( pattern.X), Math.floor( pattern.Y), Math.floor( otherPattern.X), Math.floor(otherPattern.Y)); - var moduleSizeEst2 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(otherPattern.X), Math.floor(otherPattern.Y), Math.floor( pattern.X), Math.floor(pattern.Y)); - if (isNaN(moduleSizeEst1)) - { - return moduleSizeEst2 / 7.0; - } - if (isNaN(moduleSizeEst2)) - { - return moduleSizeEst1 / 7.0; - } - // Average them, and divide by 7 since we've counted the width of 3 black modules, - // and 1 white and 1 black module on either side. Ergo, divide sum by 14. - return (moduleSizeEst1 + moduleSizeEst2) / 14.0; - } - - - this.calculateModuleSize=function( topLeft, topRight, bottomLeft) - { - // Take the average - return (this.calculateModuleSizeOneWay(topLeft, topRight) + this.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0; - } - - this.distance=function( pattern1, pattern2) - { - xDiff = pattern1.X - pattern2.X; - yDiff = pattern1.Y - pattern2.Y; - return Math.sqrt( (xDiff * xDiff + yDiff * yDiff)); - } - this.computeDimension=function( topLeft, topRight, bottomLeft, moduleSize) - { - - var tltrCentersDimension = Math.round(this.distance(topLeft, topRight) / moduleSize); - var tlblCentersDimension = Math.round(this.distance(topLeft, bottomLeft) / moduleSize); - var dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; - switch (dimension & 0x03) - { - - // mod 4 - case 0: - dimension++; - break; - // 1? do nothing - - case 2: - dimension--; - break; - - case 3: - throw "Error"; - } - return dimension; - } - - this.findAlignmentInRegion=function( overallEstModuleSize, estAlignmentX, estAlignmentY, allowanceFactor) - { - // Look for an alignment pattern (3 modules in size) around where it - // should be - var allowance = Math.floor (allowanceFactor * overallEstModuleSize); - var alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance); - var alignmentAreaRightX = Math.min(qrcode.width - 1, estAlignmentX + allowance); - if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) - { - throw "Error"; - } - - var alignmentAreaTopY = Math.max(0, estAlignmentY - allowance); - var alignmentAreaBottomY = Math.min(qrcode.height - 1, estAlignmentY + allowance); - - var alignmentFinder = new AlignmentPatternFinder(this.image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, this.resultPointCallback); - return alignmentFinder.find(); - } - - this.createTransform=function( topLeft, topRight, bottomLeft, alignmentPattern, dimension) - { - var dimMinusThree = dimension - 3.5; - var bottomRightX; - var bottomRightY; - var sourceBottomRightX; - var sourceBottomRightY; - if (alignmentPattern != null) - { - bottomRightX = alignmentPattern.X; - bottomRightY = alignmentPattern.Y; - sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0; - } - else - { - // Don't have an alignment pattern, just make up the bottom-right point - bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X; - bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y; - sourceBottomRightX = sourceBottomRightY = dimMinusThree; - } - - var transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y); - - return transform; - } - - this.sampleGrid=function( image, transform, dimension) - { - - var sampler = GridSampler; - return sampler.sampleGrid3(image, dimension, transform); - } - - this.processFinderPatternInfo = function( info) - { - - var topLeft = info.TopLeft; - var topRight = info.TopRight; - var bottomLeft = info.BottomLeft; - - var moduleSize = this.calculateModuleSize(topLeft, topRight, bottomLeft); - if (moduleSize < 1.0) - { - throw "Error"; - } - var dimension = this.computeDimension(topLeft, topRight, bottomLeft, moduleSize); - var provisionalVersion = Version.getProvisionalVersionForDimension(dimension); - var modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; - - var alignmentPattern = null; - // Anything above version 1 has an alignment pattern - if (provisionalVersion.AlignmentPatternCenters.length > 0) - { - - // Guess where a "bottom right" finder pattern would have been - var bottomRightX = topRight.X - topLeft.X + bottomLeft.X; - var bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; - - // Estimate that alignment pattern is closer by 3 modules - // from "bottom right" to known top left location - var correctionToTopLeft = 1.0 - 3.0 / modulesBetweenFPCenters; - var estAlignmentX = Math.floor (topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); - var estAlignmentY = Math.floor (topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); - - // Kind of arbitrary -- expand search radius before giving up - for (var i = 4; i <= 16; i <<= 1) - { - //try - //{ - alignmentPattern = this.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i); - break; - //} - //catch (re) - //{ - // try next round - //} - } - // If we didn't find alignment pattern... well try anyway without it - } - - var transform = this.createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); - - var bits = this.sampleGrid(this.image, transform, dimension); - - var points; - if (alignmentPattern == null) - { - points = new Array(bottomLeft, topLeft, topRight); - } - else - { - points = new Array(bottomLeft, topLeft, topRight, alignmentPattern); - } - return new DetectorResult(bits, points); - } - - - - this.detect=function() - { - var info = new FinderPatternFinder().findFinderPattern(this.image); - - return this.processFinderPatternInfo(info); - } -} -// Source: src/formatinf.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -var FORMAT_INFO_MASK_QR = 0x5412; -var FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(0x5412, 0x00), new Array(0x5125, 0x01), new Array(0x5E7C, 0x02), new Array(0x5B4B, 0x03), new Array(0x45F9, 0x04), new Array(0x40CE, 0x05), new Array(0x4F97, 0x06), new Array(0x4AA0, 0x07), new Array(0x77C4, 0x08), new Array(0x72F3, 0x09), new Array(0x7DAA, 0x0A), new Array(0x789D, 0x0B), new Array(0x662F, 0x0C), new Array(0x6318, 0x0D), new Array(0x6C41, 0x0E), new Array(0x6976, 0x0F), new Array(0x1689, 0x10), new Array(0x13BE, 0x11), new Array(0x1CE7, 0x12), new Array(0x19D0, 0x13), new Array(0x0762, 0x14), new Array(0x0255, 0x15), new Array(0x0D0C, 0x16), new Array(0x083B, 0x17), new Array(0x355F, 0x18), new Array(0x3068, 0x19), new Array(0x3F31, 0x1A), new Array(0x3A06, 0x1B), new Array(0x24B4, 0x1C), new Array(0x2183, 0x1D), new Array(0x2EDA, 0x1E), new Array(0x2BED, 0x1F)); -var BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); - - -function FormatInformation(formatInfo) -{ - this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); - this.dataMask = (formatInfo & 0x07); - - this.__defineGetter__("ErrorCorrectionLevel", function() - { - return this.errorCorrectionLevel; - }); - this.__defineGetter__("DataMask", function() - { - return this.dataMask; - }); - this.GetHashCode=function() - { - return (this.errorCorrectionLevel.ordinal() << 3) | dataMask; - } - this.Equals=function( o) - { - var other = o; - return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask; - } -} - -FormatInformation.numBitsDiffering=function( a, b) -{ - a ^= b; // a now has a 1 bit exactly where its bit differs with b's - // Count bits set quickly with a series of lookups: - return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(URShift(a, 28) & 0x0F)]; -} - -FormatInformation.decodeFormatInformation=function( maskedFormatInfo) -{ - var formatInfo = FormatInformation.doDecodeFormatInformation(maskedFormatInfo); - if (formatInfo != null) - { - return formatInfo; - } - // Should return null, but, some QR codes apparently - // do not mask this info. Try again by actually masking the pattern - // first - return FormatInformation.doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR); -} -FormatInformation.doDecodeFormatInformation=function( maskedFormatInfo) -{ - // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing - var bestDifference = 0xffffffff; - var bestFormatInfo = 0; - for (var i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) - { - var decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i]; - var targetInfo = decodeInfo[0]; - if (targetInfo == maskedFormatInfo) - { - // Found an exact match - return new FormatInformation(decodeInfo[1]); - } - var bitsDifference = this.numBitsDiffering(maskedFormatInfo, targetInfo); - if (bitsDifference < bestDifference) - { - bestFormatInfo = decodeInfo[1]; - bestDifference = bitsDifference; - } - } - // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits - // differing means we found a match - if (bestDifference <= 3) - { - return new FormatInformation(bestFormatInfo); - } - return null; -} - - -// Source: src/errorlevel.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function ErrorCorrectionLevel(ordinal, bits, name) -{ - this.ordinal_Renamed_Field = ordinal; - this.bits = bits; - this.name = name; - this.__defineGetter__("Bits", function() - { - return this.bits; - }); - this.__defineGetter__("Name", function() - { - return this.name; - }); - this.ordinal=function() - { - return this.ordinal_Renamed_Field; - } -} - -ErrorCorrectionLevel.forBits=function( bits) -{ - if (bits < 0 || bits >= FOR_BITS.length) - { - throw "ArgumentException"; - } - return FOR_BITS[bits]; -} - -var L = new ErrorCorrectionLevel(0, 0x01, "L"); -var M = new ErrorCorrectionLevel(1, 0x00, "M"); -var Q = new ErrorCorrectionLevel(2, 0x03, "Q"); -var H = new ErrorCorrectionLevel(3, 0x02, "H"); -var FOR_BITS = new Array( M, L, H, Q); - -// Source: src/bitmat.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function BitMatrix( width, height) -{ - if(!height) - height=width; - if (width < 1 || height < 1) - { - throw "Both dimensions must be greater than 0"; - } - this.width = width; - this.height = height; - var rowSize = width >> 5; - if ((width & 0x1f) != 0) - { - rowSize++; - } - this.rowSize = rowSize; - this.bits = new Array(rowSize * height); - for(var i=0;i> 5); - return ((URShift(this.bits[offset], (x & 0x1f))) & 1) != 0; - } - this.set_Renamed=function( x, y) - { - var offset = y * this.rowSize + (x >> 5); - this.bits[offset] |= 1 << (x & 0x1f); - } - this.flip=function( x, y) - { - var offset = y * this.rowSize + (x >> 5); - this.bits[offset] ^= 1 << (x & 0x1f); - } - this.clear=function() - { - var max = this.bits.length; - for (var i = 0; i < max; i++) - { - this.bits[i] = 0; - } - } - this.setRegion=function( left, top, width, height) - { - if (top < 0 || left < 0) - { - throw "Left and top must be nonnegative"; - } - if (height < 1 || width < 1) - { - throw "Height and width must be at least 1"; - } - var right = left + width; - var bottom = top + height; - if (bottom > this.height || right > this.width) - { - throw "The region must fit inside the matrix"; - } - for (var y = top; y < bottom; y++) - { - var offset = y * this.rowSize; - for (var x = left; x < right; x++) - { - this.bits[offset + (x >> 5)] |= 1 << (x & 0x1f); - } - } - } -} -// Source: src/datablock.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function DataBlock(numDataCodewords, codewords) -{ - this.numDataCodewords = numDataCodewords; - this.codewords = codewords; - - this.__defineGetter__("NumDataCodewords", function() - { - return this.numDataCodewords; - }); - this.__defineGetter__("Codewords", function() - { - return this.codewords; - }); -} - -DataBlock.getDataBlocks=function(rawCodewords, version, ecLevel) -{ - - if (rawCodewords.length != version.TotalCodewords) - { - throw "ArgumentException"; - } - - // Figure out the number and size of data blocks used by this version and - // error correction level - var ecBlocks = version.getECBlocksForLevel(ecLevel); - - // First count the total number of data blocks - var totalBlocks = 0; - var ecBlockArray = ecBlocks.getECBlocks(); - for (var i = 0; i < ecBlockArray.length; i++) - { - totalBlocks += ecBlockArray[i].Count; - } - - // Now establish DataBlocks of the appropriate size and number of data codewords - var result = new Array(totalBlocks); - var numResultBlocks = 0; - for (var j = 0; j < ecBlockArray.length; j++) - { - var ecBlock = ecBlockArray[j]; - for (var i = 0; i < ecBlock.Count; i++) - { - var numDataCodewords = ecBlock.DataCodewords; - var numBlockCodewords = ecBlocks.ECCodewordsPerBlock + numDataCodewords; - result[numResultBlocks++] = new DataBlock(numDataCodewords, new Array(numBlockCodewords)); - } - } - - // All blocks have the same amount of data, except that the last n - // (where n may be 0) have 1 more byte. Figure out where these start. - var shorterBlocksTotalCodewords = result[0].codewords.length; - var longerBlocksStartAt = result.length - 1; - while (longerBlocksStartAt >= 0) - { - var numCodewords = result[longerBlocksStartAt].codewords.length; - if (numCodewords == shorterBlocksTotalCodewords) - { - break; - } - longerBlocksStartAt--; - } - longerBlocksStartAt++; - - var shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ECCodewordsPerBlock; - // The last elements of result may be 1 element longer; - // first fill out as many elements as all of them have - var rawCodewordsOffset = 0; - for (var i = 0; i < shorterBlocksNumDataCodewords; i++) - { - for (var j = 0; j < numResultBlocks; j++) - { - result[j].codewords[i] = rawCodewords[rawCodewordsOffset++]; - } - } - // Fill out the last data block in the longer ones - for (var j = longerBlocksStartAt; j < numResultBlocks; j++) - { - result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++]; - } - // Now add in error correction blocks - var max = result[0].codewords.length; - for (var i = shorterBlocksNumDataCodewords; i < max; i++) - { - for (var j = 0; j < numResultBlocks; j++) - { - var iOffset = j < longerBlocksStartAt?i:i + 1; - result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++]; - } - } - return result; -} - -// Source: src/bmparser.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function BitMatrixParser(bitMatrix) -{ - var dimension = bitMatrix.Dimension; - if (dimension < 21 || (dimension & 0x03) != 1) - { - throw "Error BitMatrixParser"; - } - this.bitMatrix = bitMatrix; - this.parsedVersion = null; - this.parsedFormatInfo = null; - - this.copyBit=function( i, j, versionBits) - { - return this.bitMatrix.get_Renamed(i, j)?(versionBits << 1) | 0x1:versionBits << 1; - } - - this.readFormatInformation=function() - { - if (this.parsedFormatInfo != null) - { - return this.parsedFormatInfo; - } - - // Read top-left format info bits - var formatInfoBits = 0; - for (var i = 0; i < 6; i++) - { - formatInfoBits = this.copyBit(i, 8, formatInfoBits); - } - // .. and skip a bit in the timing pattern ... - formatInfoBits = this.copyBit(7, 8, formatInfoBits); - formatInfoBits = this.copyBit(8, 8, formatInfoBits); - formatInfoBits = this.copyBit(8, 7, formatInfoBits); - // .. and skip a bit in the timing pattern ... - for (var j = 5; j >= 0; j--) - { - formatInfoBits = this.copyBit(8, j, formatInfoBits); - } - - this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); - if (this.parsedFormatInfo != null) - { - return this.parsedFormatInfo; - } - - // Hmm, failed. Try the top-right/bottom-left pattern - var dimension = this.bitMatrix.Dimension; - formatInfoBits = 0; - var iMin = dimension - 8; - for (var i = dimension - 1; i >= iMin; i--) - { - formatInfoBits = this.copyBit(i, 8, formatInfoBits); - } - for (var j = dimension - 7; j < dimension; j++) - { - formatInfoBits = this.copyBit(8, j, formatInfoBits); - } - - this.parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits); - if (this.parsedFormatInfo != null) - { - return this.parsedFormatInfo; - } - throw "Error readFormatInformation"; - } - this.readVersion=function() - { - - if (this.parsedVersion != null) - { - return this.parsedVersion; - } - - var dimension = this.bitMatrix.Dimension; - - var provisionalVersion = (dimension - 17) >> 2; - if (provisionalVersion <= 6) - { - return Version.getVersionForNumber(provisionalVersion); - } - - // Read top-right version info: 3 wide by 6 tall - var versionBits = 0; - var ijMin = dimension - 11; - for (var j = 5; j >= 0; j--) - { - for (var i = dimension - 9; i >= ijMin; i--) - { - versionBits = this.copyBit(i, j, versionBits); - } - } - - this.parsedVersion = Version.decodeVersionInformation(versionBits); - if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension) - { - return this.parsedVersion; - } - - // Hmm, failed. Try bottom left: 6 wide by 3 tall - versionBits = 0; - for (var i = 5; i >= 0; i--) - { - for (var j = dimension - 9; j >= ijMin; j--) - { - versionBits = this.copyBit(i, j, versionBits); - } - } - - this.parsedVersion = Version.decodeVersionInformation(versionBits); - if (this.parsedVersion != null && this.parsedVersion.DimensionForVersion == dimension) - { - return this.parsedVersion; - } - throw "Error readVersion"; - } - this.readCodewords=function() - { - - var formatInfo = this.readFormatInformation(); - var version = this.readVersion(); - - // Get the data mask for the format used in this QR Code. This will exclude - // some bits from reading as we wind through the bit matrix. - var dataMask = DataMask.forReference( formatInfo.DataMask); - var dimension = this.bitMatrix.Dimension; - dataMask.unmaskBitMatrix(this.bitMatrix, dimension); - - var functionPattern = version.buildFunctionPattern(); - - var readingUp = true; - var result = new Array(version.TotalCodewords); - var resultOffset = 0; - var currentByte = 0; - var bitsRead = 0; - // Read columns in pairs, from right to left - for (var j = dimension - 1; j > 0; j -= 2) - { - if (j == 6) - { - // Skip whole column with vertical alignment pattern; - // saves time and makes the other code proceed more cleanly - j--; - } - // Read alternatingly from bottom to top then top to bottom - for (var count = 0; count < dimension; count++) - { - var i = readingUp?dimension - 1 - count:count; - for (var col = 0; col < 2; col++) - { - // Ignore bits covered by the function pattern - if (!functionPattern.get_Renamed(j - col, i)) - { - // Read a bit - bitsRead++; - currentByte <<= 1; - if (this.bitMatrix.get_Renamed(j - col, i)) - { - currentByte |= 1; - } - // If we've made a whole byte, save it off - if (bitsRead == 8) - { - result[resultOffset++] = currentByte; - bitsRead = 0; - currentByte = 0; - } - } - } - } - readingUp ^= true; // readingUp = !readingUp; // switch directions - } - if (resultOffset != version.TotalCodewords) - { - throw "Error readCodewords"; - } - return result; - } -} -// Source: src/datamask.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -DataMask = {}; - -DataMask.forReference = function(reference) -{ - if (reference < 0 || reference > 7) - { - throw "System.ArgumentException"; - } - return DataMask.DATA_MASKS[reference]; -} - -function DataMask000() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - return ((i + j) & 0x01) == 0; - } -} - -function DataMask001() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - return (i & 0x01) == 0; - } -} - -function DataMask010() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - return j % 3 == 0; - } -} - -function DataMask011() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - return (i + j) % 3 == 0; - } -} - -function DataMask100() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - return (((URShift(i, 1)) + (j / 3)) & 0x01) == 0; - } -} - -function DataMask101() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - var temp = i * j; - return (temp & 0x01) + (temp % 3) == 0; - } -} - -function DataMask110() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - var temp = i * j; - return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; - } -} -function DataMask111() -{ - this.unmaskBitMatrix=function(bits, dimension) - { - for (var i = 0; i < dimension; i++) - { - for (var j = 0; j < dimension; j++) - { - if (this.isMasked(i, j)) - { - bits.flip(j, i); - } - } - } - } - this.isMasked=function( i, j) - { - return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; - } -} - -DataMask.DATA_MASKS = new Array(new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111()); - - -// Source: src/rsdecoder.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function ReedSolomonDecoder(field) -{ - this.field = field; - this.decode=function(received, twoS) - { - var poly = new GF256Poly(this.field, received); - var syndromeCoefficients = new Array(twoS); - for(var i=0;i= b's - if (a.Degree < b.Degree) - { - var temp = a; - a = b; - b = temp; - } - - var rLast = a; - var r = b; - var sLast = this.field.One; - var s = this.field.Zero; - var tLast = this.field.Zero; - var t = this.field.One; - - // Run Euclidean algorithm until r's degree is less than R/2 - while (r.Degree >= Math.floor(R / 2)) - { - var rLastLast = rLast; - var sLastLast = sLast; - var tLastLast = tLast; - rLast = r; - sLast = s; - tLast = t; - - // Divide rLastLast by rLast, with quotient in q and remainder in r - if (rLast.Zero) - { - // Oops, Euclidean algorithm already terminated? - throw "r_{i-1} was zero"; - } - r = rLastLast; - var q = this.field.Zero; - var denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree); - var dltInverse = this.field.inverse(denominatorLeadingTerm); - while (r.Degree >= rLast.Degree && !r.Zero) - { - var degreeDiff = r.Degree - rLast.Degree; - var scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse); - q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale)); - r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)); - //r.EXE(); - } - - s = q.multiply1(sLast).addOrSubtract(sLastLast); - t = q.multiply1(tLast).addOrSubtract(tLastLast); - } - - var sigmaTildeAtZero = t.getCoefficient(0); - if (sigmaTildeAtZero == 0) - { - throw "ReedSolomonException sigmaTilde(0) was zero"; - } - - var inverse = this.field.inverse(sigmaTildeAtZero); - var sigma = t.multiply2(inverse); - var omega = r.multiply2(inverse); - return new Array(sigma, omega); - } - this.findErrorLocations=function( errorLocator) - { - // This is a direct application of Chien's search - var numErrors = errorLocator.Degree; - if (numErrors == 1) - { - // shortcut - return new Array(errorLocator.getCoefficient(1)); - } - var result = new Array(numErrors); - var e = 0; - for (var i = 1; i < 256 && e < numErrors; i++) - { - if (errorLocator.evaluateAt(i) == 0) - { - result[e] = this.field.inverse(i); - e++; - } - } - if (e != numErrors) - { - throw "Error locator degree does not match number of roots"; - } - return result; - } - this.findErrorMagnitudes=function( errorEvaluator, errorLocations, dataMatrix) - { - // This is directly applying Forney's Formula - var s = errorLocations.length; - var result = new Array(s); - for (var i = 0; i < s; i++) - { - var xiInverse = this.field.inverse(errorLocations[i]); - var denominator = 1; - for (var j = 0; j < s; j++) - { - if (i != j) - { - denominator = this.field.multiply(denominator, GF256.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse))); - } - } - result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator)); - // Thanks to sanfordsquires for this fix: - if (dataMatrix) - { - result[i] = this.field.multiply(result[i], xiInverse); - } - } - return result; - } -} -// Source: src/gf256poly.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function GF256Poly(field, coefficients) -{ - if (coefficients == null || coefficients.length == 0) - { - throw "System.ArgumentException"; - } - this.field = field; - var coefficientsLength = coefficients.length; - if (coefficientsLength > 1 && coefficients[0] == 0) - { - // Leading term must be non-zero for anything except the constant polynomial "0" - var firstNonZero = 1; - while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) - { - firstNonZero++; - } - if (firstNonZero == coefficientsLength) - { - this.coefficients = field.Zero.coefficients; - } - else - { - this.coefficients = new Array(coefficientsLength - firstNonZero); - for(var i=0;i largerCoefficients.length) - { - var temp = smallerCoefficients; - smallerCoefficients = largerCoefficients; - largerCoefficients = temp; - } - var sumDiff = new Array(largerCoefficients.length); - var lengthDiff = largerCoefficients.length - smallerCoefficients.length; - // Copy high-order terms only found in higher-degree polynomial's coefficients - //Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff); - for(var ci=0;ci= other.Degree && !remainder.Zero) - { - var degreeDifference = remainder.Degree - other.Degree; - var scale = this.field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm); - var term = other.multiplyByMonomial(degreeDifference, scale); - var iterationQuotient = this.field.buildMonomial(degreeDifference, scale); - quotient = quotient.addOrSubtract(iterationQuotient); - remainder = remainder.addOrSubtract(term); - } - - return new Array(quotient, remainder); - } -} -// Source: src/gf256.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function GF256( primitive) -{ - this.expTable = new Array(256); - this.logTable = new Array(256); - var x = 1; - for (var i = 0; i < 256; i++) - { - this.expTable[i] = x; - x <<= 1; // x = x * 2; we're assuming the generator alpha is 2 - if (x >= 0x100) - { - x ^= primitive; - } - } - for (var i = 0; i < 255; i++) - { - this.logTable[this.expTable[i]] = i; - } - // logTable[0] == 0 but this should never be used - var at0=new Array(1);at0[0]=0; - this.zero = new GF256Poly(this, new Array(at0)); - var at1=new Array(1);at1[0]=1; - this.one = new GF256Poly(this, new Array(at1)); - - this.__defineGetter__("Zero", function() - { - return this.zero; - }); - this.__defineGetter__("One", function() - { - return this.one; - }); - this.buildMonomial=function( degree, coefficient) - { - if (degree < 0) - { - throw "System.ArgumentException"; - } - if (coefficient == 0) - { - return zero; - } - var coefficients = new Array(degree + 1); - for(var i=0;iqrcode.maxImgSize) - { - var ir = image.width / image.height; - nheight = Math.sqrt(qrcode.maxImgSize/ir); - nwidth=ir*nheight; - } - - canvas_qr.width = nwidth; - canvas_qr.height = nheight; - - context.drawImage(image, 0, 0, canvas_qr.width, canvas_qr.height ); - qrcode.width = canvas_qr.width; - qrcode.height = canvas_qr.height; - try{ - qrcode.imagedata = context.getImageData(0, 0, canvas_qr.width, canvas_qr.height); - }catch(e){ - qrcode.result = "Cross domain image reading not supported in your browser! Save it to your computer then drag and drop the file!"; - if(qrcode.callback!=null) - qrcode.callback(qrcode.result); - return; - } - - try - { - qrcode.result = qrcode.process(context); - } - catch(e) - { - console.log(e); - qrcode.result = "error decoding QR Code"; - } - if(qrcode.callback!=null) - qrcode.callback(qrcode.result); - } - image.src = src; - } -} - -qrcode.isUrl = function(s) -{ - var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/; - return regexp.test(s); -} - -qrcode.decode_url = function (s) -{ - var escaped = ""; - try{ - escaped = escape( s ); - } - catch(e) - { - console.log(e); - escaped = s; - } - var ret = ""; - try{ - ret = decodeURIComponent( escaped ); - } - catch(e) - { - console.log(e); - ret = escaped; - } - return ret; -} - -qrcode.decode_utf8 = function ( s ) -{ - if(qrcode.isUrl(s)) - return qrcode.decode_url(s); - else - return s; -} - -qrcode.process = function(ctx){ - - var start = new Date().getTime(); - - var image = qrcode.grayScaleToBitmap(qrcode.grayscale()); - //var image = qrcode.binarize(128); - - if(qrcode.debug) - { - for (var y = 0; y < qrcode.height; y++) - { - for (var x = 0; x < qrcode.width; x++) - { - var point = (x * 4) + (y * qrcode.width * 4); - qrcode.imagedata.data[point] = image[x+y*qrcode.width]?0:0; - qrcode.imagedata.data[point+1] = image[x+y*qrcode.width]?0:0; - qrcode.imagedata.data[point+2] = image[x+y*qrcode.width]?255:0; - } - } - ctx.putImageData(qrcode.imagedata, 0, 0); - } - - //var finderPatternInfo = new FinderPatternFinder().findFinderPattern(image); - - var detector = new Detector(image); - - var qRCodeMatrix = detector.detect(); - - /*for (var y = 0; y < qRCodeMatrix.bits.Height; y++) - { - for (var x = 0; x < qRCodeMatrix.bits.Width; x++) - { - var point = (x * 4*2) + (y*2 * qrcode.width * 4); - qrcode.imagedata.data[point] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0; - qrcode.imagedata.data[point+1] = qRCodeMatrix.bits.get_Renamed(x,y)?0:0; - qrcode.imagedata.data[point+2] = qRCodeMatrix.bits.get_Renamed(x,y)?255:0; - } - }*/ - if(qrcode.debug) - ctx.putImageData(qrcode.imagedata, 0, 0); - - var reader = Decoder.decode(qRCodeMatrix.bits); - var data = reader.DataByte; - var str=""; - for(var i=0;i minmax[ax][ay][1]) - minmax[ax][ay][1] = target; - } - } - //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2; - } - } - var middle = new Array(numSqrtArea); - for (var i3 = 0; i3 < numSqrtArea; i3++) - { - middle[i3] = new Array(numSqrtArea); - } - for (var ay = 0; ay < numSqrtArea; ay++) - { - for (var ax = 0; ax < numSqrtArea; ax++) - { - middle[ax][ay] = Math.floor((minmax[ax][ay][0] + minmax[ax][ay][1]) / 2); - //Console.out.print(middle[ax][ay] + ","); - } - //Console.out.println(""); - } - //Console.out.println(""); - - return middle; -} - -qrcode.grayScaleToBitmap=function(grayScale) -{ - var middle = qrcode.getMiddleBrightnessPerArea(grayScale); - var sqrtNumArea = middle.length; - var areaWidth = Math.floor(qrcode.width / sqrtNumArea); - var areaHeight = Math.floor(qrcode.height / sqrtNumArea); - var bitmap = new Array(qrcode.height*qrcode.width); - - for (var ay = 0; ay < sqrtNumArea; ay++) - { - for (var ax = 0; ax < sqrtNumArea; ax++) - { - for (var dy = 0; dy < areaHeight; dy++) - { - for (var dx = 0; dx < areaWidth; dx++) - { - bitmap[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] = (grayScale[areaWidth * ax + dx+ (areaHeight * ay + dy)*qrcode.width] < middle[ax][ay])?true:false; - } - } - } - } - return bitmap; -} - -qrcode.grayscale = function(){ - var ret = new Array(qrcode.width*qrcode.height); - for (var y = 0; y < qrcode.height; y++) - { - for (var x = 0; x < qrcode.width; x++) - { - var gray = qrcode.getPixel(x, y); - - ret[x+y*qrcode.width] = gray; - } - } - return ret; -} - - - - -function URShift( number, bits) -{ - if (number >= 0) - return number >> bits; - else - return (number >> bits) + (2 << ~bits); -} - - -// Source: src/findpat.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -var MIN_SKIP = 3; -var MAX_MODULES = 57; -var INTEGER_MATH_SHIFT = 8; -var CENTER_QUORUM = 2; - -qrcode.orderBestPatterns=function(patterns) - { - - function distance( pattern1, pattern2) - { - xDiff = pattern1.X - pattern2.X; - yDiff = pattern1.Y - pattern2.Y; - return Math.sqrt( (xDiff * xDiff + yDiff * yDiff)); - } - - /// Returns the z component of the cross product between vectors BC and BA. - function crossProductZ( pointA, pointB, pointC) - { - var bX = pointB.x; - var bY = pointB.y; - return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); - } - - - // Find distances between pattern centers - var zeroOneDistance = distance(patterns[0], patterns[1]); - var oneTwoDistance = distance(patterns[1], patterns[2]); - var zeroTwoDistance = distance(patterns[0], patterns[2]); - - var pointA, pointB, pointC; - // Assume one closest to other two is B; A and C will just be guesses at first - if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) - { - pointB = patterns[0]; - pointA = patterns[1]; - pointC = patterns[2]; - } - else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) - { - pointB = patterns[1]; - pointA = patterns[0]; - pointC = patterns[2]; - } - else - { - pointB = patterns[2]; - pointA = patterns[0]; - pointC = patterns[1]; - } - - // Use cross product to figure out whether A and C are correct or flipped. - // This asks whether BC x BA has a positive z component, which is the arrangement - // we want for A, B, C. If it's negative, then we've got it flipped around and - // should swap A and C. - if (crossProductZ(pointA, pointB, pointC) < 0.0) - { - var temp = pointA; - pointA = pointC; - pointC = temp; - } - - patterns[0] = pointA; - patterns[1] = pointB; - patterns[2] = pointC; - } - - -function FinderPattern(posX, posY, estimatedModuleSize) -{ - this.x=posX; - this.y=posY; - this.count = 1; - this.estimatedModuleSize = estimatedModuleSize; - - this.__defineGetter__("EstimatedModuleSize", function() - { - return this.estimatedModuleSize; - }); - this.__defineGetter__("Count", function() - { - return this.count; - }); - this.__defineGetter__("X", function() - { - return this.x; - }); - this.__defineGetter__("Y", function() - { - return this.y; - }); - this.incrementCount = function() - { - this.count++; - } - this.aboutEquals=function( moduleSize, i, j) - { - if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) - { - var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); - return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0; - } - return false; - } - -} - -function FinderPatternInfo(patternCenters) -{ - this.bottomLeft = patternCenters[0]; - this.topLeft = patternCenters[1]; - this.topRight = patternCenters[2]; - this.__defineGetter__("BottomLeft", function() - { - return this.bottomLeft; - }); - this.__defineGetter__("TopLeft", function() - { - return this.topLeft; - }); - this.__defineGetter__("TopRight", function() - { - return this.topRight; - }); -} - -function FinderPatternFinder() -{ - this.image=null; - this.possibleCenters = []; - this.hasSkipped = false; - this.crossCheckStateCount = new Array(0,0,0,0,0); - this.resultPointCallback = null; - - this.__defineGetter__("CrossCheckStateCount", function() - { - this.crossCheckStateCount[0] = 0; - this.crossCheckStateCount[1] = 0; - this.crossCheckStateCount[2] = 0; - this.crossCheckStateCount[3] = 0; - this.crossCheckStateCount[4] = 0; - return this.crossCheckStateCount; - }); - - this.foundPatternCross=function( stateCount) - { - var totalModuleSize = 0; - for (var i = 0; i < 5; i++) - { - var count = stateCount[i]; - if (count == 0) - { - return false; - } - totalModuleSize += count; - } - if (totalModuleSize < 7) - { - return false; - } - var moduleSize = Math.floor((totalModuleSize << INTEGER_MATH_SHIFT) / 7); - var maxVariance = Math.floor(moduleSize / 2); - // Allow less than 50% variance from 1-1-3-1-1 proportions - return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance && Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance && Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance; - } - this.centerFromEnd=function( stateCount, end) - { - return (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0; - } - this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal) - { - var image = this.image; - - var maxI = qrcode.height; - var stateCount = this.CrossCheckStateCount; - - // Start counting up from center - var i = startI; - while (i >= 0 && image[centerJ + i*qrcode.width]) - { - stateCount[2]++; - i--; - } - if (i < 0) - { - return NaN; - } - while (i >= 0 && !image[centerJ +i*qrcode.width] && stateCount[1] <= maxCount) - { - stateCount[1]++; - i--; - } - // If already too many modules in this state or ran off the edge: - if (i < 0 || stateCount[1] > maxCount) - { - return NaN; - } - while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount) - { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) - { - return NaN; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image[centerJ +i*qrcode.width]) - { - stateCount[2]++; - i++; - } - if (i == maxI) - { - return NaN; - } - while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[3] < maxCount) - { - stateCount[3]++; - i++; - } - if (i == maxI || stateCount[3] >= maxCount) - { - return NaN; - } - while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[4] < maxCount) - { - stateCount[4]++; - i++; - } - if (stateCount[4] >= maxCount) - { - return NaN; - } - - // If we found a finder-pattern-like section, but its size is more than 40% different than - // the original, assume it's a false positive - var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) - { - return NaN; - } - - return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN; - } - this.crossCheckHorizontal=function( startJ, centerI, maxCount, originalStateCountTotal) - { - var image = this.image; - - var maxJ = qrcode.width; - var stateCount = this.CrossCheckStateCount; - - var j = startJ; - while (j >= 0 && image[j+ centerI*qrcode.width]) - { - stateCount[2]++; - j--; - } - if (j < 0) - { - return NaN; - } - while (j >= 0 && !image[j+ centerI*qrcode.width] && stateCount[1] <= maxCount) - { - stateCount[1]++; - j--; - } - if (j < 0 || stateCount[1] > maxCount) - { - return NaN; - } - while (j >= 0 && image[j+ centerI*qrcode.width] && stateCount[0] <= maxCount) - { - stateCount[0]++; - j--; - } - if (stateCount[0] > maxCount) - { - return NaN; - } - - j = startJ + 1; - while (j < maxJ && image[j+ centerI*qrcode.width]) - { - stateCount[2]++; - j++; - } - if (j == maxJ) - { - return NaN; - } - while (j < maxJ && !image[j+ centerI*qrcode.width] && stateCount[3] < maxCount) - { - stateCount[3]++; - j++; - } - if (j == maxJ || stateCount[3] >= maxCount) - { - return NaN; - } - while (j < maxJ && image[j+ centerI*qrcode.width] && stateCount[4] < maxCount) - { - stateCount[4]++; - j++; - } - if (stateCount[4] >= maxCount) - { - return NaN; - } - - // If we found a finder-pattern-like section, but its size is significantly different than - // the original, assume it's a false positive - var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) - { - return NaN; - } - - return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, j):NaN; - } - this.handlePossibleCenter=function( stateCount, i, j) - { - var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; - var centerJ = this.centerFromEnd(stateCount, j); //float - var centerI = this.crossCheckVertical(i, Math.floor( centerJ), stateCount[2], stateCountTotal); //float - if (!isNaN(centerI)) - { - // Re-cross check - centerJ = this.crossCheckHorizontal(Math.floor( centerJ), Math.floor( centerI), stateCount[2], stateCountTotal); - if (!isNaN(centerJ)) - { - var estimatedModuleSize = stateCountTotal / 7.0; - var found = false; - var max = this.possibleCenters.length; - for (var index = 0; index < max; index++) - { - var center = this.possibleCenters[index]; - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) - { - center.incrementCount(); - found = true; - break; - } - } - if (!found) - { - var point = new FinderPattern(centerJ, centerI, estimatedModuleSize); - this.possibleCenters.push(point); - if (this.resultPointCallback != null) - { - this.resultPointCallback.foundPossibleResultPoint(point); - } - } - return true; - } - } - return false; - } - - this.selectBestPatterns=function() - { - - var startSize = this.possibleCenters.length; - if (startSize < 3) - { - // Couldn't find enough finder patterns - throw "Couldn't find enough finder patterns"; - } - - // Filter outlier possibilities whose module size is too different - if (startSize > 3) - { - // But we can only afford to do so if we have at least 4 possibilities to choose from - var totalModuleSize = 0.0; - var square = 0.0; - for (var i = 0; i < startSize; i++) - { - //totalModuleSize += this.possibleCenters[i].EstimatedModuleSize; - var centerValue=this.possibleCenters[i].EstimatedModuleSize; - totalModuleSize += centerValue; - square += (centerValue * centerValue); - } - var average = totalModuleSize / startSize; - this.possibleCenters.sort(function(center1,center2) { - var dA=Math.abs(center2.EstimatedModuleSize - average); - var dB=Math.abs(center1.EstimatedModuleSize - average); - if (dA < dB) { - return (-1); - } else if (dA == dB) { - return 0; - } else { - return 1; - } - }); - - var stdDev = Math.sqrt(square / startSize - average * average); - var limit = Math.max(0.2 * average, stdDev); - for (var i = 0; i < this.possibleCenters.length && this.possibleCenters.length > 3; i++) - { - var pattern = this.possibleCenters[i]; - //if (Math.abs(pattern.EstimatedModuleSize - average) > 0.2 * average) - if (Math.abs(pattern.EstimatedModuleSize - average) > limit) - { - this.possibleCenters.splice(i, 1); - i--; - } - } - } - - if (this.possibleCenters.length > 3) - { - // Throw away all but those first size candidate points we found. - this.possibleCenters.sort(function(a, b){ - if (a.count > b.count){return -1;} - if (a.count < b.count){return 1;} - return 0; - }); - } - - return new Array( this.possibleCenters[0], this.possibleCenters[1], this.possibleCenters[2]); - } - - this.findRowSkip=function() - { - var max = this.possibleCenters.length; - if (max <= 1) - { - return 0; - } - var firstConfirmedCenter = null; - for (var i = 0; i < max; i++) - { - var center = this.possibleCenters[i]; - if (center.Count >= CENTER_QUORUM) - { - if (firstConfirmedCenter == null) - { - firstConfirmedCenter = center; - } - else - { - // We have two confirmed centers - // How far down can we skip before resuming looking for the next - // pattern? In the worst case, only the difference between the - // difference in the x / y coordinates of the two centers. - // This is the case where you find top left last. - this.hasSkipped = true; - return Math.floor ((Math.abs(firstConfirmedCenter.X - center.X) - Math.abs(firstConfirmedCenter.Y - center.Y)) / 2); - } - } - } - return 0; - } - - this.haveMultiplyConfirmedCenters=function() - { - var confirmedCount = 0; - var totalModuleSize = 0.0; - var max = this.possibleCenters.length; - for (var i = 0; i < max; i++) - { - var pattern = this.possibleCenters[i]; - if (pattern.Count >= CENTER_QUORUM) - { - confirmedCount++; - totalModuleSize += pattern.EstimatedModuleSize; - } - } - if (confirmedCount < 3) - { - return false; - } - // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive" - // and that we need to keep looking. We detect this by asking if the estimated module sizes - // vary too much. We arbitrarily say that when the total deviation from average exceeds - // 5% of the total module size estimates, it's too much. - var average = totalModuleSize / max; - var totalDeviation = 0.0; - for (var i = 0; i < max; i++) - { - pattern = this.possibleCenters[i]; - totalDeviation += Math.abs(pattern.EstimatedModuleSize - average); - } - return totalDeviation <= 0.05 * totalModuleSize; - } - - this.findFinderPattern = function(image){ - var tryHarder = false; - this.image=image; - var maxI = qrcode.height; - var maxJ = qrcode.width; - var iSkip = Math.floor((3 * maxI) / (4 * MAX_MODULES)); - if (iSkip < MIN_SKIP || tryHarder) - { - iSkip = MIN_SKIP; - } - - var done = false; - var stateCount = new Array(5); - for (var i = iSkip - 1; i < maxI && !done; i += iSkip) - { - // Get a row of black/white values - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - var currentState = 0; - for (var j = 0; j < maxJ; j++) - { - if (image[j+i*qrcode.width] ) - { - // Black pixel - if ((currentState & 1) == 1) - { - // Counting white pixels - currentState++; - } - stateCount[currentState]++; - } - else - { - // White pixel - if ((currentState & 1) == 0) - { - // Counting black pixels - if (currentState == 4) - { - // A winner? - if (this.foundPatternCross(stateCount)) - { - // Yes - var confirmed = this.handlePossibleCenter(stateCount, i, j); - if (confirmed) - { - // Start examining every other line. Checking each line turned out to be too - // expensive and didn't improve performance. - iSkip = 2; - if (this.hasSkipped) - { - done = this.haveMultiplyConfirmedCenters(); - } - else - { - var rowSkip = this.findRowSkip(); - if (rowSkip > stateCount[2]) - { - // Skip rows between row of lower confirmed center - // and top of presumed third confirmed center - // but back up a bit to get a full chance of detecting - // it, entire width of center of finder pattern - - // Skip by rowSkip, but back off by stateCount[2] (size of last center - // of pattern we saw) to be conservative, and also back off by iSkip which - // is about to be re-added - i += rowSkip - stateCount[2] - iSkip; - j = maxJ - 1; - } - } - } - else - { - // Advance to next black pixel - do - { - j++; - } - while (j < maxJ && !image[j + i*qrcode.width]); - j--; // back up to that last white pixel - } - // Clear state to start looking again - currentState = 0; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - stateCount[3] = 0; - stateCount[4] = 0; - } - else - { - // No, shift counts back by two - stateCount[0] = stateCount[2]; - stateCount[1] = stateCount[3]; - stateCount[2] = stateCount[4]; - stateCount[3] = 1; - stateCount[4] = 0; - currentState = 3; - } - } - else - { - stateCount[++currentState]++; - } - } - else - { - // Counting white pixels - stateCount[currentState]++; - } - } - } - if (this.foundPatternCross(stateCount)) - { - var confirmed = this.handlePossibleCenter(stateCount, i, maxJ); - if (confirmed) - { - iSkip = stateCount[0]; - if (this.hasSkipped) - { - // Found a third one - done = haveMultiplyConfirmedCenters(); - } - } - } - } - - var patternInfo = this.selectBestPatterns(); - qrcode.orderBestPatterns(patternInfo); - - return new FinderPatternInfo(patternInfo); - }; -} - -// Source: src/alignpat.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function AlignmentPattern(posX, posY, estimatedModuleSize) -{ - this.x=posX; - this.y=posY; - this.count = 1; - this.estimatedModuleSize = estimatedModuleSize; - - this.__defineGetter__("EstimatedModuleSize", function() - { - return this.estimatedModuleSize; - }); - this.__defineGetter__("Count", function() - { - return this.count; - }); - this.__defineGetter__("X", function() - { - return Math.floor(this.x); - }); - this.__defineGetter__("Y", function() - { - return Math.floor(this.y); - }); - this.incrementCount = function() - { - this.count++; - } - this.aboutEquals=function( moduleSize, i, j) - { - if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) - { - var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); - return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0; - } - return false; - } - -} - -function AlignmentPatternFinder( image, startX, startY, width, height, moduleSize, resultPointCallback) -{ - this.image = image; - this.possibleCenters = new Array(); - this.startX = startX; - this.startY = startY; - this.width = width; - this.height = height; - this.moduleSize = moduleSize; - this.crossCheckStateCount = new Array(0,0,0); - this.resultPointCallback = resultPointCallback; - - this.centerFromEnd=function(stateCount, end) - { - return (end - stateCount[2]) - stateCount[1] / 2.0; - } - this.foundPatternCross = function(stateCount) - { - var moduleSize = this.moduleSize; - var maxVariance = moduleSize / 2.0; - for (var i = 0; i < 3; i++) - { - if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) - { - return false; - } - } - return true; - } - - this.crossCheckVertical=function( startI, centerJ, maxCount, originalStateCountTotal) - { - var image = this.image; - - var maxI = qrcode.height; - var stateCount = this.crossCheckStateCount; - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - - // Start counting up from center - var i = startI; - while (i >= 0 && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount) - { - stateCount[1]++; - i--; - } - // If already too many modules in this state or ran off the edge: - if (i < 0 || stateCount[1] > maxCount) - { - return NaN; - } - while (i >= 0 && !image[centerJ + i*qrcode.width] && stateCount[0] <= maxCount) - { - stateCount[0]++; - i--; - } - if (stateCount[0] > maxCount) - { - return NaN; - } - - // Now also count down from center - i = startI + 1; - while (i < maxI && image[centerJ + i*qrcode.width] && stateCount[1] <= maxCount) - { - stateCount[1]++; - i++; - } - if (i == maxI || stateCount[1] > maxCount) - { - return NaN; - } - while (i < maxI && !image[centerJ + i*qrcode.width] && stateCount[2] <= maxCount) - { - stateCount[2]++; - i++; - } - if (stateCount[2] > maxCount) - { - return NaN; - } - - var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) - { - return NaN; - } - - return this.foundPatternCross(stateCount)?this.centerFromEnd(stateCount, i):NaN; - } - - this.handlePossibleCenter=function( stateCount, i, j) - { - var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; - var centerJ = this.centerFromEnd(stateCount, j); - var centerI = this.crossCheckVertical(i, Math.floor (centerJ), 2 * stateCount[1], stateCountTotal); - if (!isNaN(centerI)) - { - var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0; - var max = this.possibleCenters.length; - for (var index = 0; index < max; index++) - { - var center = this.possibleCenters[index]; - // Look for about the same center and module size: - if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) - { - return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); - } - } - // Hadn't found this before; save it - var point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); - this.possibleCenters.push(point); - if (this.resultPointCallback != null) - { - this.resultPointCallback.foundPossibleResultPoint(point); - } - } - return null; - } - - this.find = function() - { - var startX = this.startX; - var height = this.height; - var maxJ = startX + width; - var middleI = startY + (height >> 1); - // We are looking for black/white/black modules in 1:1:1 ratio; - // this tracks the number of black/white/black modules seen so far - var stateCount = new Array(0,0,0); - for (var iGen = 0; iGen < height; iGen++) - { - // Search from middle outwards - var i = middleI + ((iGen & 0x01) == 0?((iGen + 1) >> 1):- ((iGen + 1) >> 1)); - stateCount[0] = 0; - stateCount[1] = 0; - stateCount[2] = 0; - var j = startX; - // Burn off leading white pixels before anything else; if we start in the middle of - // a white run, it doesn't make sense to count its length, since we don't know if the - // white run continued to the left of the start point - while (j < maxJ && !image[j + qrcode.width* i]) - { - j++; - } - var currentState = 0; - while (j < maxJ) - { - if (image[j + i*qrcode.width]) - { - // Black pixel - if (currentState == 1) - { - // Counting black pixels - stateCount[currentState]++; - } - else - { - // Counting white pixels - if (currentState == 2) - { - // A winner? - if (this.foundPatternCross(stateCount)) - { - // Yes - var confirmed = this.handlePossibleCenter(stateCount, i, j); - if (confirmed != null) - { - return confirmed; - } - } - stateCount[0] = stateCount[2]; - stateCount[1] = 1; - stateCount[2] = 0; - currentState = 1; - } - else - { - stateCount[++currentState]++; - } - } - } - else - { - // White pixel - if (currentState == 1) - { - // Counting black pixels - currentState++; - } - stateCount[currentState]++; - } - j++; - } - if (this.foundPatternCross(stateCount)) - { - var confirmed = this.handlePossibleCenter(stateCount, i, maxJ); - if (confirmed != null) - { - return confirmed; - } - } - } - - // Hmm, nothing we saw was observed and confirmed twice. If we had - // any guess at all, return it. - if (!(this.possibleCenters.length == 0)) - { - return this.possibleCenters[0]; - } - - throw "Couldn't find enough alignment patterns"; - } - -} -// Source: src/databr.js -/* - Ported to JavaScript by Lazar Laszlo 2011 - - lazarsoft@gmail.com, www.lazarsoft.info - -*/ - -/* -* -* Copyright 2007 ZXing authors -* -* 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. -*/ - - -function QRCodeDataBlockReader(blocks, version, numErrorCorrectionCode) -{ - this.blockPointer = 0; - this.bitPointer = 7; - this.dataLength = 0; - this.blocks = blocks; - this.numErrorCorrectionCode = numErrorCorrectionCode; - if (version <= 9) - this.dataLengthMode = 0; - else if (version >= 10 && version <= 26) - this.dataLengthMode = 1; - else if (version >= 27 && version <= 40) - this.dataLengthMode = 2; - - this.getNextBits = function( numBits) - { - var bits = 0; - if (numBits < this.bitPointer + 1) - { - // next word fits into current data block - var mask = 0; - for (var i = 0; i < numBits; i++) - { - mask += (1 << i); - } - mask <<= (this.bitPointer - numBits + 1); - - bits = (this.blocks[this.blockPointer] & mask) >> (this.bitPointer - numBits + 1); - this.bitPointer -= numBits; - return bits; - } - else if (numBits < this.bitPointer + 1 + 8) - { - // next word crosses 2 data blocks - var mask1 = 0; - for (var i = 0; i < this.bitPointer + 1; i++) - { - mask1 += (1 << i); - } - bits = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); - this.blockPointer++; - bits += ((this.blocks[this.blockPointer]) >> (8 - (numBits - (this.bitPointer + 1)))); - - this.bitPointer = this.bitPointer - numBits % 8; - if (this.bitPointer < 0) - { - this.bitPointer = 8 + this.bitPointer; - } - return bits; - } - else if (numBits < this.bitPointer + 1 + 16) - { - // next word crosses 3 data blocks - var mask1 = 0; // mask of first block - var mask3 = 0; // mask of 3rd block - //bitPointer + 1 : number of bits of the 1st block - //8 : number of the 2nd block (note that use already 8bits because next word uses 3 data blocks) - //numBits - (bitPointer + 1 + 8) : number of bits of the 3rd block - for (var i = 0; i < this.bitPointer + 1; i++) - { - mask1 += (1 << i); - } - var bitsFirstBlock = (this.blocks[this.blockPointer] & mask1) << (numBits - (this.bitPointer + 1)); - this.blockPointer++; - - var bitsSecondBlock = this.blocks[this.blockPointer] << (numBits - (this.bitPointer + 1 + 8)); - this.blockPointer++; - - for (var i = 0; i < numBits - (this.bitPointer + 1 + 8); i++) - { - mask3 += (1 << i); - } - mask3 <<= 8 - (numBits - (this.bitPointer + 1 + 8)); - var bitsThirdBlock = (this.blocks[this.blockPointer] & mask3) >> (8 - (numBits - (this.bitPointer + 1 + 8))); - - bits = bitsFirstBlock + bitsSecondBlock + bitsThirdBlock; - this.bitPointer = this.bitPointer - (numBits - 8) % 8; - if (this.bitPointer < 0) - { - this.bitPointer = 8 + this.bitPointer; - } - return bits; - } - else - { - return 0; - } - } - this.NextMode=function() - { - if ((this.blockPointer > this.blocks.length - this.numErrorCorrectionCode - 2)) - return 0; - else - return this.getNextBits(4); - } - this.getDataLength=function( modeIndicator) - { - var index = 0; - while (true) - { - if ((modeIndicator >> index) == 1) - break; - index++; - } - - return this.getNextBits(qrcode.sizeOfDataLengthInfo[this.dataLengthMode][index]); - } - this.getRomanAndFigureString=function( dataLength) - { - var length = dataLength; - var intData = 0; - var strData = ""; - var tableRomanAndFigure = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'); - do - { - if (length > 1) - { - intData = this.getNextBits(11); - var firstLetter = Math.floor(intData / 45); - var secondLetter = intData % 45; - strData += tableRomanAndFigure[firstLetter]; - strData += tableRomanAndFigure[secondLetter]; - length -= 2; - } - else if (length == 1) - { - intData = this.getNextBits(6); - strData += tableRomanAndFigure[intData]; - length -= 1; - } - } - while (length > 0); - - return strData; - } - this.getFigureString=function( dataLength) - { - var length = dataLength; - var intData = 0; - var strData = ""; - do - { - if (length >= 3) - { - intData = this.getNextBits(10); - if (intData < 100) - strData += "0"; - if (intData < 10) - strData += "0"; - length -= 3; - } - else if (length == 2) - { - intData = this.getNextBits(7); - if (intData < 10) - strData += "0"; - length -= 2; - } - else if (length == 1) - { - intData = this.getNextBits(4); - length -= 1; - } - strData += intData; - } - while (length > 0); - - return strData; - } - this.get8bitByteArray=function( dataLength) - { - var length = dataLength; - var intData = 0; - var output = new Array(); - - do - { - intData = this.getNextBits(8); - output.push( intData); - length--; - } - while (length > 0); - return output; - } - this.getKanjiString=function( dataLength) - { - var length = dataLength; - var intData = 0; - var unicodeString = ""; - do - { - intData = getNextBits(13); - var lowerByte = intData % 0xC0; - var higherByte = intData / 0xC0; - - var tempWord = (higherByte << 8) + lowerByte; - var shiftjisWord = 0; - if (tempWord + 0x8140 <= 0x9FFC) - { - // between 8140 - 9FFC on Shift_JIS character set - shiftjisWord = tempWord + 0x8140; - } - else - { - // between E040 - EBBF on Shift_JIS character set - shiftjisWord = tempWord + 0xC140; - } - - //var tempByte = new Array(0,0); - //tempByte[0] = (sbyte) (shiftjisWord >> 8); - //tempByte[1] = (sbyte) (shiftjisWord & 0xFF); - //unicodeString += new String(SystemUtils.ToCharArray(SystemUtils.ToByteArray(tempByte))); - unicodeString += String.fromCharCode(shiftjisWord); - length--; - } - while (length > 0); - - - return unicodeString; - } - - this.__defineGetter__("DataByte", function() - { - var output = new Array(); - var MODE_NUMBER = 1; - var MODE_ROMAN_AND_NUMBER = 2; - var MODE_8BIT_BYTE = 4; - var MODE_KANJI = 8; - do - { - var mode = this.NextMode(); - //canvas.println("mode: " + mode); - if (mode == 0) - { - if (output.length > 0) - break; - else - throw "Empty data block"; - } - //if (mode != 1 && mode != 2 && mode != 4 && mode != 8) - // break; - //} - if (mode != MODE_NUMBER && mode != MODE_ROMAN_AND_NUMBER && mode != MODE_8BIT_BYTE && mode != MODE_KANJI) - { - /* canvas.println("Invalid mode: " + mode); - mode = guessMode(mode); - canvas.println("Guessed mode: " + mode); */ - throw "Invalid mode: " + mode + " in (block:" + this.blockPointer + " bit:" + this.bitPointer + ")"; - } - dataLength = this.getDataLength(mode); - if (dataLength < 1) - throw "Invalid data length: " + dataLength; - //canvas.println("length: " + dataLength); - switch (mode) - { - - case MODE_NUMBER: - //canvas.println("Mode: Figure"); - var temp_str = this.getFigureString(dataLength); - var ta = new Array(temp_str.length); - for(var j=0;j 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } - } - - return to; - } - - var updateInProgress = false; - - // Moment prototype object - function Moment(config) { - copyConfig(this, config); - this._d = new Date(+config._d); - // Prevent infinite loop in case updateOffset creates new moment - // objects. - if (updateInProgress === false) { - updateInProgress = true; - utils_hooks__hooks.updateOffset(this); - updateInProgress = false; - } - } - - function isMoment (obj) { - return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } - - return value; - } - - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function Locale() { - } - - var locales = {}; - var globalLocale; - - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // pick the locale from the array - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { - var i = 0, j, next, locale, split; - - while (i < names.length) { - split = normalizeLocale(names[i]).split('-'); - j = split.length; - next = normalizeLocale(names[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - locale = loadLocale(split.slice(0, j).join('-')); - if (locale) { - return locale; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return null; - } - - function loadLocale(name) { - var oldLocale = null; - // TODO: Find a better way to register and load all the locales in Node - if (!locales[name] && typeof module !== 'undefined' && - module && module.exports) { - try { - oldLocale = globalLocale._abbr; - require('./locale/' + name); - // because defineLocale currently also sets the global locale, we - // want to undo that for lazy loaded locales - locale_locales__getSetGlobalLocale(oldLocale); - } catch (e) { } - } - return locales[name]; - } - - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - function locale_locales__getSetGlobalLocale (key, values) { - var data; - if (key) { - if (typeof values === 'undefined') { - data = locale_locales__getLocale(key); - } - else { - data = defineLocale(key, values); - } - - if (data) { - // moment.duration._locale = moment._locale = data; - globalLocale = data; - } - } - - return globalLocale._abbr; - } - - function defineLocale (name, values) { - if (values !== null) { - values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); - } - locales[name].set(values); - - // backwards compat for now: also set the locale - locale_locales__getSetGlobalLocale(name); - - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - } - - // returns locale data - function locale_locales__getLocale (key) { - var locale; - - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } - - if (!key) { - return globalLocale; - } - - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - - return chooseLocale(key); - } - - var aliases = {}; - - function addUnitAlias (unit, shorthand) { - var lowerCase = unit.toLowerCase(); - aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; - } - - function normalizeUnits(units) { - return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined; - } - - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - - return normalizedInput; - } - - function makeGetSet (unit, keepTime) { - return function (value) { - if (value != null) { - get_set__set(this, unit, value); - utils_hooks__hooks.updateOffset(this, keepTime); - return this; - } else { - return get_set__get(this, unit); - } - }; - } - - function get_set__get (mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } - - function get_set__set (mom, unit, value) { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - - // MOMENTS - - function getSet (units, value) { - var unit; - if (typeof units === 'object') { - for (unit in units) { - this.set(unit, units[unit]); - } - } else { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - return this[units](value); - } - } - return this; - } - - function zeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; - } - - var formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g; - - var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; - - var formatFunctions = {}; - - var formatTokenFunctions = {}; - - // token: 'M' - // padded: ['MM', 2] - // ordinal: 'Mo' - // callback: function () { this.month() + 1 } - function addFormatToken (token, padded, ordinal, callback) { - var func = callback; - if (typeof callback === 'string') { - func = function () { - return this[callback](); - }; - } - if (token) { - formatTokenFunctions[token] = func; - } - if (padded) { - formatTokenFunctions[padded[0]] = function () { - return zeroFill(func.apply(this, arguments), padded[1], padded[2]); - }; - } - if (ordinal) { - formatTokenFunctions[ordinal] = function () { - return this.localeData().ordinal(func.apply(this, arguments), token); - }; - } - } - - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - - format = expandFormat(format, m.localeData()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, locale) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } - - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - - return format; - } - - var match1 = /\d/; // 0 - 9 - var match2 = /\d\d/; // 00 - 99 - var match3 = /\d{3}/; // 000 - 999 - var match4 = /\d{4}/; // 0000 - 9999 - var match6 = /[+-]?\d{6}/; // -999999 - 999999 - var match1to2 = /\d\d?/; // 0 - 99 - var match1to3 = /\d{1,3}/; // 0 - 999 - var match1to4 = /\d{1,4}/; // 0 - 9999 - var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999 - - var matchUnsigned = /\d+/; // 0 - inf - var matchSigned = /[+-]?\d+/; // -inf - inf - - var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z - - var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123 - - // any word (or two) characters or numbers including two/three word month in arabic. - var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; - - var regexes = {}; - - function addRegexToken (token, regex, strictRegex) { - regexes[token] = typeof regex === 'function' ? regex : function (isStrict) { - return (isStrict && strictRegex) ? strictRegex : regex; - }; - } - - function getParseRegexForToken (token, config) { - if (!hasOwnProp(regexes, token)) { - return new RegExp(unescapeFormat(token)); - } - - return regexes[token](config._strict, config._locale); - } - - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function unescapeFormat(s) { - return s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - var tokens = {}; - - function addParseToken (token, callback) { - var i, func = callback; - if (typeof token === 'string') { - token = [token]; - } - if (typeof callback === 'number') { - func = function (input, array) { - array[callback] = toInt(input); - }; - } - for (i = 0; i < token.length; i++) { - tokens[token[i]] = func; - } - } - - function addWeekParseToken (token, callback) { - addParseToken(token, function (input, array, config, token) { - config._w = config._w || {}; - callback(input, config._w, config, token); - }); - } - - function addTimeToArrayFromToken(token, input, config) { - if (input != null && hasOwnProp(tokens, token)) { - tokens[token](input, config._a, config, token); - } - } - - var YEAR = 0; - var MONTH = 1; - var DATE = 2; - var HOUR = 3; - var MINUTE = 4; - var SECOND = 5; - var MILLISECOND = 6; - - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } - - // FORMATTING - - addFormatToken('M', ['MM', 2], 'Mo', function () { - return this.month() + 1; - }); - - addFormatToken('MMM', 0, 0, function (format) { - return this.localeData().monthsShort(this, format); - }); - - addFormatToken('MMMM', 0, 0, function (format) { - return this.localeData().months(this, format); - }); - - // ALIASES - - addUnitAlias('month', 'M'); - - // PARSING - - addRegexToken('M', match1to2); - addRegexToken('MM', match1to2, match2); - addRegexToken('MMM', matchWord); - addRegexToken('MMMM', matchWord); - - addParseToken(['M', 'MM'], function (input, array) { - array[MONTH] = toInt(input) - 1; - }); - - addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { - var month = config._locale.monthsParse(input, token, config._strict); - // if we didn't find a month name, mark the date as invalid. - if (month != null) { - array[MONTH] = month; - } else { - getParsingFlags(config).invalidMonth = input; - } - }); - - // LOCALES - - var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); - function localeMonths (m) { - return this._months[m.month()]; - } - - var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); - function localeMonthsShort (m) { - return this._monthsShort[m.month()]; - } - - function localeMonthsParse (monthName, format, strict) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - this._longMonthsParse = []; - this._shortMonthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - mom = create_utc__createUTC([2000, i]); - if (strict && !this._longMonthsParse[i]) { - this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); - this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); - } - if (!strict && !this._monthsParse[i]) { - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { - return i; - } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { - return i; - } else if (!strict && this._monthsParse[i].test(monthName)) { - return i; - } - } - } - - // MOMENTS - - function setMonth (mom, value) { - var dayOfMonth; - - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } - } - - dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } - - function getSetMonth (value) { - if (value != null) { - setMonth(this, value); - utils_hooks__hooks.updateOffset(this, true); - return this; - } else { - return get_set__get(this, 'Month'); - } - } - - function getDaysInMonth () { - return daysInMonth(this.year(), this.month()); - } - - function checkOverflow (m) { - var overflow; - var a = m._a; - - if (a && getParsingFlags(m).overflow === -2) { - overflow = - a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : - a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : - a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR : - a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : - a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : - a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - - getParsingFlags(m).overflow = overflow; - } - - return m; - } - - function warn(msg) { - if (utils_hooks__hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); - } - } - - function deprecate(msg, fn) { - var firstTime = true, - msgWithStack = msg + '\n' + (new Error()).stack; - - return extend(function () { - if (firstTime) { - warn(msgWithStack); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); - } - - var deprecations = {}; - - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - warn(msg); - deprecations[name] = true; - } - } - - utils_hooks__hooks.suppressDeprecationWarnings = false; - - var from_string__isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/; - - var isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ]; - - // iso time formats and regexes - var isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ]; - - var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; - - // date from iso format - function configFromISO(config) { - var i, l, - string = config._i, - match = from_string__isoRegex.exec(string); - - if (match) { - getParsingFlags(config).iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(matchOffset)) { - config._f += 'Z'; - } - configFromStringAndFormat(config); - } else { - config._isValid = false; - } - } - - // date from iso format or fallback - function configFromString(config) { - var matched = aspNetJsonRegex.exec(config._i); - - if (matched !== null) { - config._d = new Date(+matched[1]); - return; - } - - configFromISO(config); - if (config._isValid === false) { - delete config._isValid; - utils_hooks__hooks.createFromInputFallback(config); - } - } - - utils_hooks__hooks.createFromInputFallback = deprecate( - 'moment construction falls back to js Date. This is ' + - 'discouraged and will be removed in upcoming major ' + - 'release. Please refer to ' + - 'https://github.com/moment/moment/issues/1407 for more info.', - function (config) { - config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); - } - ); - - function createDate (y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); - - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } - - function createUTCDate (y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } - - addFormatToken(0, ['YY', 2], 0, function () { - return this.year() % 100; - }); - - addFormatToken(0, ['YYYY', 4], 0, 'year'); - addFormatToken(0, ['YYYYY', 5], 0, 'year'); - addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); - - // ALIASES - - addUnitAlias('year', 'y'); - - // PARSING - - addRegexToken('Y', matchSigned); - addRegexToken('YY', match1to2, match2); - addRegexToken('YYYY', match1to4, match4); - addRegexToken('YYYYY', match1to6, match6); - addRegexToken('YYYYYY', match1to6, match6); - - addParseToken(['YYYY', 'YYYYY', 'YYYYYY'], YEAR); - addParseToken('YY', function (input, array) { - array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input); - }); - - // HELPERS - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - // HOOKS - - utils_hooks__hooks.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; - - // MOMENTS - - var getSetYear = makeGetSet('FullYear', false); - - function getIsLeapYear () { - return isLeapYear(this.year()); - } - - addFormatToken('w', ['ww', 2], 'wo', 'week'); - addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); - - // ALIASES - - addUnitAlias('week', 'w'); - addUnitAlias('isoWeek', 'W'); - - // PARSING - - addRegexToken('w', match1to2); - addRegexToken('ww', match1to2, match2); - addRegexToken('W', match1to2); - addRegexToken('WW', match1to2, match2); - - addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) { - week[token.substr(0, 1)] = toInt(input); - }); - - // HELPERS - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = local__createLocal(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - // LOCALES - - function localeWeek (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - } - - var defaultLocaleWeek = { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }; - - function localeFirstDayOfWeek () { - return this._week.dow; - } - - function localeFirstDayOfYear () { - return this._week.doy; - } - - // MOMENTS - - function getSetWeek (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - } - - function getSetISOWeek (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - } - - addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); - - // ALIASES - - addUnitAlias('dayOfYear', 'DDD'); - - // PARSING - - addRegexToken('DDD', match1to3); - addRegexToken('DDDD', match3); - addParseToken(['DDD', 'DDDD'], function (input, array, config) { - config._dayOfYear = toInt(input); - }); - - // HELPERS - - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = createUTCDate(year, 0, 1).getUTCDay(); - var daysToAdd; - var dayOfYear; - - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - - return { - year : dayOfYear > 0 ? year : year - 1, - dayOfYear : dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } - - // MOMENTS - - function getSetDayOfYear (input) { - var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - } - - // Pick the first defined of two or three arguments. - function defaults(a, b, c) { - if (a != null) { - return a; - } - if (b != null) { - return b; - } - return c; - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()]; - } - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function configFromArray (config) { - var i, date, input = [], currentDate, yearToUse; - - if (config._d) { - return; - } - - currentDate = currentDateArray(config); - - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } - - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); - - if (config._dayOfYear > daysInYear(yearToUse)) { - getParsingFlags(config)._overflowDayOfYear = true; - } - - date = createUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - // Check for 24:00:00.000 - if (config._a[HOUR] === 24 && - config._a[MINUTE] === 0 && - config._a[SECOND] === 0 && - config._a[MILLISECOND] === 0) { - config._nextDay = true; - config._a[HOUR] = 0; - } - - config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input); - // Apply timezone offset from input. The actual utcOffset can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); - } - - if (config._nextDay) { - config._a[HOUR] = 24; - } - } - - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; - - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year); - week = defaults(w.W, 1); - weekday = defaults(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; - - weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year); - week = defaults(w.w, 1); - - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - - utils_hooks__hooks.ISO_8601 = function () {}; - - // date from string and format string - function configFromStringAndFormat(config) { - // TODO: Move this to another part of the creation flow to prevent circular deps - if (config._f === utils_hooks__hooks.ISO_8601) { - configFromISO(config); - return; - } - - config._a = []; - getParsingFlags(config).empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - getParsingFlags(config).unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - getParsingFlags(config).empty = false; - } - else { - getParsingFlags(config).unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - getParsingFlags(config).unusedTokens.push(token); - } - } - - // add remaining unparsed input length to the string - getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - getParsingFlags(config).unusedInput.push(string); - } - - // clear _12h flag if hour is <= 12 - if (getParsingFlags(config).bigHour === true && - config._a[HOUR] <= 12 && - config._a[HOUR] > 0) { - getParsingFlags(config).bigHour = undefined; - } - // handle meridiem - config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); - - configFromArray(config); - checkOverflow(config); - } - - - function meridiemFixWrap (locale, hour, meridiem) { - var isPm; - - if (meridiem == null) { - // nothing to do - return hour; - } - if (locale.meridiemHour != null) { - return locale.meridiemHour(hour, meridiem); - } else if (locale.isPM != null) { - // Fallback - isPm = locale.isPM(meridiem); - if (isPm && hour < 12) { - hour += 12; - } - if (!isPm && hour === 12) { - hour = 0; - } - return hour; - } else { - // this is not supposed to happen - return hour; - } - } - - function configFromStringAndArray(config) { - var tempConfig, - bestMoment, - - scoreToBeat, - i, - currentScore; - - if (config._f.length === 0) { - getParsingFlags(config).invalidFormat = true; - config._d = new Date(NaN); - return; - } - - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._f = config._f[i]; - configFromStringAndFormat(tempConfig); - - if (!valid__isValid(tempConfig)) { - continue; - } - - // if there is any input that was not parsed add a penalty for that format - currentScore += getParsingFlags(tempConfig).charsLeftOver; - - //or tokens - currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; - - getParsingFlags(tempConfig).score = currentScore; - - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - - extend(config, bestMoment || tempConfig); - } - - function configFromObject(config) { - if (config._d) { - return; - } - - var i = normalizeObjectUnits(config._i); - config._a = [i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond]; - - configFromArray(config); - } - - function createFromConfig (config) { - var input = config._i, - format = config._f, - res; - - config._locale = config._locale || locale_locales__getLocale(config._l); - - if (input === null || (format === undefined && input === '')) { - return valid__createInvalid({nullInput: true}); - } - - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } - - if (isMoment(input)) { - return new Moment(checkOverflow(input)); - } else if (isArray(format)) { - configFromStringAndArray(config); - } else if (format) { - configFromStringAndFormat(config); - } else if (isDate(input)) { - config._d = input; - } else { - configFromInput(config); - } - - res = new Moment(checkOverflow(config)); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } - - return res; - } - - function configFromInput(config) { - var input = config._i; - if (input === undefined) { - config._d = new Date(); - } else if (isDate(input)) { - config._d = new Date(+input); - } else if (typeof input === 'string') { - configFromString(config); - } else if (isArray(input)) { - config._a = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - configFromArray(config); - } else if (typeof(input) === 'object') { - configFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); - } else { - utils_hooks__hooks.createFromInputFallback(config); - } - } - - function createLocalOrUTC (input, format, locale, strict, isUTC) { - var c = {}; - - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c._isAMomentObject = true; - c._useUTC = c._isUTC = isUTC; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - - return createFromConfig(c); - } - - function local__createLocal (input, format, locale, strict) { - return createLocalOrUTC(input, format, locale, strict, false); - } - - var prototypeMin = deprecate( - 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', - function () { - var other = local__createLocal.apply(null, arguments); - return other < this ? this : other; - } - ); - - var prototypeMax = deprecate( - 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', - function () { - var other = local__createLocal.apply(null, arguments); - return other > this ? this : other; - } - ); - - // Pick a moment m from moments so that m[fn](other) is true for all - // other. This relies on the function fn to be transitive. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return local__createLocal(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } - - // TODO: Use [].sort instead? - function min () { - var args = [].slice.call(arguments, 0); - - return pickBy('isBefore', args); - } - - function max () { - var args = [].slice.call(arguments, 0); - - return pickBy('isAfter', args); - } - - function Duration (duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - - this._data = {}; - - this._locale = locale_locales__getLocale(); - - this._bubble(); - } - - function isDuration (obj) { - return obj instanceof Duration; - } - - function offset (token, separator) { - addFormatToken(token, 0, 0, function () { - var offset = this.utcOffset(); - var sign = '+'; - if (offset < 0) { - offset = -offset; - sign = '-'; - } - return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2); - }); - } - - offset('Z', ':'); - offset('ZZ', ''); - - // PARSING - - addRegexToken('Z', matchOffset); - addRegexToken('ZZ', matchOffset); - addParseToken(['Z', 'ZZ'], function (input, array, config) { - config._useUTC = true; - config._tzm = offsetFromString(input); - }); - - // HELPERS - - // timezone chunker - // '+10:00' > ['10', '00'] - // '-1530' > ['-15', '30'] - var chunkOffset = /([\+\-]|\d\d)/gi; - - function offsetFromString(string) { - var matches = ((string || '').match(matchOffset) || []); - var chunk = matches[matches.length - 1] || []; - var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; - var minutes = +(parts[1] * 60) + toInt(parts[2]); - - return parts[0] === '+' ? minutes : -minutes; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function cloneWithOffset(input, model) { - var res, diff; - if (model._isUTC) { - res = model.clone(); - diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res); - // Use low-level api, because this fn is low-level api. - res._d.setTime(+res._d + diff); - utils_hooks__hooks.updateOffset(res, false); - return res; - } else { - return local__createLocal(input).local(); - } - return model._isUTC ? local__createLocal(input).zone(model._offset || 0) : local__createLocal(input).local(); - } - - function getDateOffset (m) { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return -Math.round(m._d.getTimezoneOffset() / 15) * 15; - } - - // HOOKS - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - utils_hooks__hooks.updateOffset = function () {}; - - // MOMENTS - - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset - // +0200, so we adjust the time as needed, to be valid. - // - // Keeping the time actually adds/subtracts (one hour) - // from the actual represented time. That is why we call updateOffset - // a second time. In case it wants us to change the offset again - // _changeInProgress == true case, then we have to adjust, because - // there is no such time in the given timezone. - function getSetOffset (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = offsetFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = getDateOffset(this); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.add(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - utils_hooks__hooks.updateOffset(this, true); - this._changeInProgress = null; - } - } - return this; - } else { - return this._isUTC ? offset : getDateOffset(this); - } - } - - function getSetZone (input, keepLocalTime) { - if (input != null) { - if (typeof input !== 'string') { - input = -input; - } - - this.utcOffset(input, keepLocalTime); - - return this; - } else { - return -this.utcOffset(); - } - } - - function setOffsetToUTC (keepLocalTime) { - return this.utcOffset(0, keepLocalTime); - } - - function setOffsetToLocal (keepLocalTime) { - if (this._isUTC) { - this.utcOffset(0, keepLocalTime); - this._isUTC = false; - - if (keepLocalTime) { - this.subtract(getDateOffset(this), 'm'); - } - } - return this; - } - - function setOffsetToParsedOffset () { - if (this._tzm) { - this.utcOffset(this._tzm); - } else if (typeof this._i === 'string') { - this.utcOffset(offsetFromString(this._i)); - } - return this; - } - - function hasAlignedHourOffset (input) { - if (!input) { - input = 0; - } - else { - input = local__createLocal(input).utcOffset(); - } - - return (this.utcOffset() - input) % 60 === 0; - } - - function isDaylightSavingTime () { - return ( - this.utcOffset() > this.clone().month(0).utcOffset() || - this.utcOffset() > this.clone().month(5).utcOffset() - ); - } - - function isDaylightSavingTimeShifted () { - if (this._a) { - var other = this._isUTC ? create_utc__createUTC(this._a) : local__createLocal(this._a); - return this.isValid() && compareArrays(this._a, other.toArray()) > 0; - } - - return false; - } - - function isLocal () { - return !this._isUTC; - } - - function isUtcOffset () { - return this._isUTC; - } - - function isUtc () { - return this._isUTC && this._offset === 0; - } - - var aspNetRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/; - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - var create__isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/; - - function create__createDuration (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - diffRes; - - if (isDuration(input)) { - duration = { - ms : input._milliseconds, - d : input._days, - M : input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y : 0, - d : toInt(match[DATE]) * sign, - h : toInt(match[HOUR]) * sign, - m : toInt(match[MINUTE]) * sign, - s : toInt(match[SECOND]) * sign, - ms : toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = create__isoRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y : parseIso(match[2], sign), - M : parseIso(match[3], sign), - d : parseIso(match[4], sign), - h : parseIso(match[5], sign), - m : parseIso(match[6], sign), - s : parseIso(match[7], sign), - w : parseIso(match[8], sign) - }; - } else if (duration == null) {// checks for null or undefined - duration = {}; - } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) { - diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to)); - - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } - - ret = new Duration(duration); - - if (isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } - - return ret; - } - - create__createDuration.fn = Duration.prototype; - - function parseIso (inp, sign) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - } - - function positiveMomentsDifference(base, other) { - var res = {milliseconds: 0, months: 0}; - - res.months = other.month() - base.month() + - (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } - - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - - return res; - } - - function momentsDifference(base, other) { - var res; - other = cloneWithOffset(other, base); - if (base.isBefore(other)) { - res = positiveMomentsDifference(base, other); - } else { - res = positiveMomentsDifference(other, base); - res.milliseconds = -res.milliseconds; - res.months = -res.months; - } - - return res; - } - - function createAdder(direction, name) { - return function (val, period) { - var dur, tmp; - //invert the arguments, but complain about it - if (period !== null && !isNaN(+period)) { - deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); - tmp = val; val = period; period = tmp; - } - - val = typeof val === 'string' ? +val : val; - dur = create__createDuration(val, period); - add_subtract__addSubtract(this, dur, direction); - return this; - }; - } - - function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding); - } - if (months) { - setMonth(mom, get_set__get(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - utils_hooks__hooks.updateOffset(mom, days || months); - } - } - - var add_subtract__add = createAdder(1, 'add'); - var add_subtract__subtract = createAdder(-1, 'subtract'); - - function moment_calendar__calendar (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're local/utc/offset or not. - var now = time || local__createLocal(), - sod = cloneWithOffset(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this, local__createLocal(now))); - } - - function clone () { - return new Moment(this); - } - - function isAfter (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = isMoment(input) ? input : local__createLocal(input); - return +this > +input; - } else { - inputMs = isMoment(input) ? +input : +local__createLocal(input); - return inputMs < +this.clone().startOf(units); - } - } - - function isBefore (input, units) { - var inputMs; - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = isMoment(input) ? input : local__createLocal(input); - return +this < +input; - } else { - inputMs = isMoment(input) ? +input : +local__createLocal(input); - return +this.clone().endOf(units) < inputMs; - } - } - - function isBetween (from, to, units) { - return this.isAfter(from, units) && this.isBefore(to, units); - } - - function isSame (input, units) { - var inputMs; - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - input = isMoment(input) ? input : local__createLocal(input); - return +this === +input; - } else { - inputMs = +local__createLocal(input); - return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units)); - } - } - - function absFloor (number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - function diff (input, units, asFloat) { - var that = cloneWithOffset(input, this), - zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4, - delta, output; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month' || units === 'quarter') { - output = monthDiff(this, that); - if (units === 'quarter') { - output = output / 3; - } else if (units === 'year') { - output = output / 12; - } - } else { - delta = this - that; - output = units === 'second' ? delta / 1e3 : // 1000 - units === 'minute' ? delta / 6e4 : // 1000 * 60 - units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - delta; - } - return asFloat ? output : absFloor(output); - } - - function monthDiff (a, b) { - // difference in months - var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), - // b is in (anchor - 1 month, anchor + 1 month) - anchor = a.clone().add(wholeMonthDiff, 'months'), - anchor2, adjust; - - if (b - anchor < 0) { - anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor - anchor2); - } else { - anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); - // linear across the month - adjust = (b - anchor) / (anchor2 - anchor); - } - - return -(wholeMonthDiff + adjust); - } - - utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; - - function toString () { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - } - - function moment_format__toISOString () { - var m = this.clone().utc(); - if (0 < m.year() && m.year() <= 9999) { - if ('function' === typeof Date.prototype.toISOString) { - // native implementation is ~50x faster, use it when we can - return this.toDate().toISOString(); - } else { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - } - - function moment_format__format (inputString) { - var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat); - return this.localeData().postformat(output); - } - - function from (time, withoutSuffix) { - if (!this.isValid()) { - return this.localeData().invalidDate(); - } - return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - } - - function fromNow (withoutSuffix) { - return this.from(local__createLocal(), withoutSuffix); - } - - function to (time, withoutSuffix) { - if (!this.isValid()) { - return this.localeData().invalidDate(); - } - return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix); - } - - function toNow (withoutSuffix) { - return this.to(local__createLocal(), withoutSuffix); - } - - function locale (key) { - var newLocaleData; - - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = locale_locales__getLocale(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - } - - var lang = deprecate( - 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ); - - function localeData () { - return this._locale; - } - - function startOf (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } - if (units === 'isoWeek') { - this.isoWeekday(1); - } - - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } - - return this; - } - - function endOf (units) { - units = normalizeUnits(units); - if (units === undefined || units === 'millisecond') { - return this; - } - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - } - - function to_type__valueOf () { - return +this._d - ((this._offset || 0) * 60000); - } - - function unix () { - return Math.floor(+this / 1000); - } - - function toDate () { - return this._offset ? new Date(+this) : this._d; - } - - function toArray () { - var m = this; - return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; - } - - function moment_valid__isValid () { - return valid__isValid(this); - } - - function parsingFlags () { - return extend({}, getParsingFlags(this)); - } - - function invalidAt () { - return getParsingFlags(this).overflow; - } - - addFormatToken(0, ['gg', 2], 0, function () { - return this.weekYear() % 100; - }); - - addFormatToken(0, ['GG', 2], 0, function () { - return this.isoWeekYear() % 100; - }); - - function addWeekYearFormatToken (token, getter) { - addFormatToken(0, [token, token.length], 0, getter); - } - - addWeekYearFormatToken('gggg', 'weekYear'); - addWeekYearFormatToken('ggggg', 'weekYear'); - addWeekYearFormatToken('GGGG', 'isoWeekYear'); - addWeekYearFormatToken('GGGGG', 'isoWeekYear'); - - // ALIASES - - addUnitAlias('weekYear', 'gg'); - addUnitAlias('isoWeekYear', 'GG'); - - // PARSING - - addRegexToken('G', matchSigned); - addRegexToken('g', matchSigned); - addRegexToken('GG', match1to2, match2); - addRegexToken('gg', match1to2, match2); - addRegexToken('GGGG', match1to4, match4); - addRegexToken('gggg', match1to4, match4); - addRegexToken('GGGGG', match1to6, match6); - addRegexToken('ggggg', match1to6, match6); - - addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) { - week[token.substr(0, 2)] = toInt(input); - }); - - addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { - week[token] = utils_hooks__hooks.parseTwoDigitYear(input); - }); - - // HELPERS - - function weeksInYear(year, dow, doy) { - return weekOfYear(local__createLocal([year, 11, 31 + dow - doy]), dow, doy).week; - } - - // MOMENTS - - function getSetWeekYear (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - } - - function getSetISOWeekYear (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - } - - function getISOWeeksInYear () { - return weeksInYear(this.year(), 1, 4); - } - - function getWeeksInYear () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - } - - addFormatToken('Q', 0, 0, 'quarter'); - - // ALIASES - - addUnitAlias('quarter', 'Q'); - - // PARSING - - addRegexToken('Q', match1); - addParseToken('Q', function (input, array) { - array[MONTH] = (toInt(input) - 1) * 3; - }); - - // MOMENTS - - function getSetQuarter (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - } - - addFormatToken('D', ['DD', 2], 'Do', 'date'); - - // ALIASES - - addUnitAlias('date', 'D'); - - // PARSING - - addRegexToken('D', match1to2); - addRegexToken('DD', match1to2, match2); - addRegexToken('Do', function (isStrict, locale) { - return isStrict ? locale._ordinalParse : locale._ordinalParseLenient; - }); - - addParseToken(['D', 'DD'], DATE); - addParseToken('Do', function (input, array) { - array[DATE] = toInt(input.match(match1to2)[0], 10); - }); - - // MOMENTS - - var getSetDayOfMonth = makeGetSet('Date', true); - - addFormatToken('d', 0, 'do', 'day'); - - addFormatToken('dd', 0, 0, function (format) { - return this.localeData().weekdaysMin(this, format); - }); - - addFormatToken('ddd', 0, 0, function (format) { - return this.localeData().weekdaysShort(this, format); - }); - - addFormatToken('dddd', 0, 0, function (format) { - return this.localeData().weekdays(this, format); - }); - - addFormatToken('e', 0, 0, 'weekday'); - addFormatToken('E', 0, 0, 'isoWeekday'); - - // ALIASES - - addUnitAlias('day', 'd'); - addUnitAlias('weekday', 'e'); - addUnitAlias('isoWeekday', 'E'); - - // PARSING - - addRegexToken('d', match1to2); - addRegexToken('e', match1to2); - addRegexToken('E', match1to2); - addRegexToken('dd', matchWord); - addRegexToken('ddd', matchWord); - addRegexToken('dddd', matchWord); - - addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config) { - var weekday = config._locale.weekdaysParse(input); - // if we didn't get a weekday name, mark the date as invalid - if (weekday != null) { - week.d = weekday; - } else { - getParsingFlags(config).invalidWeekday = input; - } - }); - - addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { - week[token] = toInt(input); - }); - - // HELPERS - - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } - - // LOCALES - - var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); - function localeWeekdays (m) { - return this._weekdays[m.day()]; - } - - var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); - function localeWeekdaysShort (m) { - return this._weekdaysShort[m.day()]; - } - - var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); - function localeWeekdaysMin (m) { - return this._weekdaysMin[m.day()]; - } - - function localeWeekdaysParse (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = local__createLocal([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - } - - // MOMENTS - - function getSetDayOfWeek (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - } - - function getSetLocaleDayOfWeek (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - } - - function getSetISODayOfWeek (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - } - - addFormatToken('H', ['HH', 2], 0, 'hour'); - addFormatToken('h', ['hh', 2], 0, function () { - return this.hours() % 12 || 12; - }); - - function meridiem (token, lowercase) { - addFormatToken(token, 0, 0, function () { - return this.localeData().meridiem(this.hours(), this.minutes(), lowercase); - }); - } - - meridiem('a', true); - meridiem('A', false); - - // ALIASES - - addUnitAlias('hour', 'h'); - - // PARSING - - function matchMeridiem (isStrict, locale) { - return locale._meridiemParse; - } - - addRegexToken('a', matchMeridiem); - addRegexToken('A', matchMeridiem); - addRegexToken('H', match1to2); - addRegexToken('h', match1to2); - addRegexToken('HH', match1to2, match2); - addRegexToken('hh', match1to2, match2); - - addParseToken(['H', 'HH'], HOUR); - addParseToken(['a', 'A'], function (input, array, config) { - config._isPm = config._locale.isPM(input); - config._meridiem = input; - }); - addParseToken(['h', 'hh'], function (input, array, config) { - array[HOUR] = toInt(input); - getParsingFlags(config).bigHour = true; - }); - - // LOCALES - - function localeIsPM (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - } - - var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i; - function localeMeridiem (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - } - - - // MOMENTS - - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - var getSetHour = makeGetSet('Hours', true); - - addFormatToken('m', ['mm', 2], 0, 'minute'); - - // ALIASES - - addUnitAlias('minute', 'm'); - - // PARSING - - addRegexToken('m', match1to2); - addRegexToken('mm', match1to2, match2); - addParseToken(['m', 'mm'], MINUTE); - - // MOMENTS - - var getSetMinute = makeGetSet('Minutes', false); - - addFormatToken('s', ['ss', 2], 0, 'second'); - - // ALIASES - - addUnitAlias('second', 's'); - - // PARSING - - addRegexToken('s', match1to2); - addRegexToken('ss', match1to2, match2); - addParseToken(['s', 'ss'], SECOND); - - // MOMENTS - - var getSetSecond = makeGetSet('Seconds', false); - - addFormatToken('S', 0, 0, function () { - return ~~(this.millisecond() / 100); - }); - - addFormatToken(0, ['SS', 2], 0, function () { - return ~~(this.millisecond() / 10); - }); - - function millisecond__milliseconds (token) { - addFormatToken(0, [token, 3], 0, 'millisecond'); - } - - millisecond__milliseconds('SSS'); - millisecond__milliseconds('SSSS'); - - // ALIASES - - addUnitAlias('millisecond', 'ms'); - - // PARSING - - addRegexToken('S', match1to3, match1); - addRegexToken('SS', match1to3, match2); - addRegexToken('SSS', match1to3, match3); - addRegexToken('SSSS', matchUnsigned); - addParseToken(['S', 'SS', 'SSS', 'SSSS'], function (input, array) { - array[MILLISECOND] = toInt(('0.' + input) * 1000); - }); - - // MOMENTS - - var getSetMillisecond = makeGetSet('Milliseconds', false); - - addFormatToken('z', 0, 0, 'zoneAbbr'); - addFormatToken('zz', 0, 0, 'zoneName'); - - // MOMENTS - - function getZoneAbbr () { - return this._isUTC ? 'UTC' : ''; - } - - function getZoneName () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - } - - var momentPrototype__proto = Moment.prototype; - - momentPrototype__proto.add = add_subtract__add; - momentPrototype__proto.calendar = moment_calendar__calendar; - momentPrototype__proto.clone = clone; - momentPrototype__proto.diff = diff; - momentPrototype__proto.endOf = endOf; - momentPrototype__proto.format = moment_format__format; - momentPrototype__proto.from = from; - momentPrototype__proto.fromNow = fromNow; - momentPrototype__proto.to = to; - momentPrototype__proto.toNow = toNow; - momentPrototype__proto.get = getSet; - momentPrototype__proto.invalidAt = invalidAt; - momentPrototype__proto.isAfter = isAfter; - momentPrototype__proto.isBefore = isBefore; - momentPrototype__proto.isBetween = isBetween; - momentPrototype__proto.isSame = isSame; - momentPrototype__proto.isValid = moment_valid__isValid; - momentPrototype__proto.lang = lang; - momentPrototype__proto.locale = locale; - momentPrototype__proto.localeData = localeData; - momentPrototype__proto.max = prototypeMax; - momentPrototype__proto.min = prototypeMin; - momentPrototype__proto.parsingFlags = parsingFlags; - momentPrototype__proto.set = getSet; - momentPrototype__proto.startOf = startOf; - momentPrototype__proto.subtract = add_subtract__subtract; - momentPrototype__proto.toArray = toArray; - momentPrototype__proto.toDate = toDate; - momentPrototype__proto.toISOString = moment_format__toISOString; - momentPrototype__proto.toJSON = moment_format__toISOString; - momentPrototype__proto.toString = toString; - momentPrototype__proto.unix = unix; - momentPrototype__proto.valueOf = to_type__valueOf; - - // Year - momentPrototype__proto.year = getSetYear; - momentPrototype__proto.isLeapYear = getIsLeapYear; - - // Week Year - momentPrototype__proto.weekYear = getSetWeekYear; - momentPrototype__proto.isoWeekYear = getSetISOWeekYear; - - // Quarter - momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter; - - // Month - momentPrototype__proto.month = getSetMonth; - momentPrototype__proto.daysInMonth = getDaysInMonth; - - // Week - momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek; - momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek; - momentPrototype__proto.weeksInYear = getWeeksInYear; - momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear; - - // Day - momentPrototype__proto.date = getSetDayOfMonth; - momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek; - momentPrototype__proto.weekday = getSetLocaleDayOfWeek; - momentPrototype__proto.isoWeekday = getSetISODayOfWeek; - momentPrototype__proto.dayOfYear = getSetDayOfYear; - - // Hour - momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour; - - // Minute - momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute; - - // Second - momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond; - - // Millisecond - momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond; - - // Offset - momentPrototype__proto.utcOffset = getSetOffset; - momentPrototype__proto.utc = setOffsetToUTC; - momentPrototype__proto.local = setOffsetToLocal; - momentPrototype__proto.parseZone = setOffsetToParsedOffset; - momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset; - momentPrototype__proto.isDST = isDaylightSavingTime; - momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted; - momentPrototype__proto.isLocal = isLocal; - momentPrototype__proto.isUtcOffset = isUtcOffset; - momentPrototype__proto.isUtc = isUtc; - momentPrototype__proto.isUTC = isUtc; - - // Timezone - momentPrototype__proto.zoneAbbr = getZoneAbbr; - momentPrototype__proto.zoneName = getZoneName; - - // Deprecations - momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth); - momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth); - momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear); - momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone); - - var momentPrototype = momentPrototype__proto; - - function moment_moment__createUnix (input) { - return local__createLocal(input * 1000); - } - - function moment_moment__createInZone () { - return local__createLocal.apply(null, arguments).parseZone(); - } - - var defaultCalendar = { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }; - - function locale_calendar__calendar (key, mom, now) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.call(mom, now) : output; - } - - var defaultLongDateFormat = { - LTS : 'h:mm:ss A', - LT : 'h:mm A', - L : 'MM/DD/YYYY', - LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM D, YYYY LT' - }; - - function longDateFormat (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - } - - var defaultInvalidDate = 'Invalid date'; - - function invalidDate () { - return this._invalidDate; - } - - var defaultOrdinal = '%d'; - var defaultOrdinalParse = /\d{1,2}/; - - function ordinal (number) { - return this._ordinal.replace('%d', number); - } - - function preParsePostFormat (string) { - return string; - } - - var defaultRelativeTime = { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }; - - function relative__relativeTime (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - } - - function pastFuture (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - } - - function locale_set__set (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - // Lenient ordinal parsing accepts just a number in addition to - // number + (possibly) stuff coming from _ordinalParseLenient. - this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source); - } - - var prototype__proto = Locale.prototype; - - prototype__proto._calendar = defaultCalendar; - prototype__proto.calendar = locale_calendar__calendar; - prototype__proto._longDateFormat = defaultLongDateFormat; - prototype__proto.longDateFormat = longDateFormat; - prototype__proto._invalidDate = defaultInvalidDate; - prototype__proto.invalidDate = invalidDate; - prototype__proto._ordinal = defaultOrdinal; - prototype__proto.ordinal = ordinal; - prototype__proto._ordinalParse = defaultOrdinalParse; - prototype__proto.preparse = preParsePostFormat; - prototype__proto.postformat = preParsePostFormat; - prototype__proto._relativeTime = defaultRelativeTime; - prototype__proto.relativeTime = relative__relativeTime; - prototype__proto.pastFuture = pastFuture; - prototype__proto.set = locale_set__set; - - // Month - prototype__proto.months = localeMonths; - prototype__proto._months = defaultLocaleMonths; - prototype__proto.monthsShort = localeMonthsShort; - prototype__proto._monthsShort = defaultLocaleMonthsShort; - prototype__proto.monthsParse = localeMonthsParse; - - // Week - prototype__proto.week = localeWeek; - prototype__proto._week = defaultLocaleWeek; - prototype__proto.firstDayOfYear = localeFirstDayOfYear; - prototype__proto.firstDayOfWeek = localeFirstDayOfWeek; - - // Day of Week - prototype__proto.weekdays = localeWeekdays; - prototype__proto._weekdays = defaultLocaleWeekdays; - prototype__proto.weekdaysMin = localeWeekdaysMin; - prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin; - prototype__proto.weekdaysShort = localeWeekdaysShort; - prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort; - prototype__proto.weekdaysParse = localeWeekdaysParse; - - // Hours - prototype__proto.isPM = localeIsPM; - prototype__proto._meridiemParse = defaultLocaleMeridiemParse; - prototype__proto.meridiem = localeMeridiem; - - function lists__get (format, index, field, setter) { - var locale = locale_locales__getLocale(); - var utc = create_utc__createUTC().set(setter, index); - return locale[field](utc, format); - } - - function list (format, index, field, count, setter) { - if (typeof format === 'number') { - index = format; - format = undefined; - } - - format = format || ''; - - if (index != null) { - return lists__get(format, index, field, setter); - } - - var i; - var out = []; - for (i = 0; i < count; i++) { - out[i] = lists__get(format, i, field, setter); - } - return out; - } - - function lists__listMonths (format, index) { - return list(format, index, 'months', 12, 'month'); - } - - function lists__listMonthsShort (format, index) { - return list(format, index, 'monthsShort', 12, 'month'); - } - - function lists__listWeekdays (format, index) { - return list(format, index, 'weekdays', 7, 'day'); - } - - function lists__listWeekdaysShort (format, index) { - return list(format, index, 'weekdaysShort', 7, 'day'); - } - - function lists__listWeekdaysMin (format, index) { - return list(format, index, 'weekdaysMin', 7, 'day'); - } - - locale_locales__getSetGlobalLocale('en', { - ordinalParse: /\d{1,2}(th|st|nd|rd)/, - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - // Side effect imports - utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale); - utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale); - - var mathAbs = Math.abs; - - function duration_abs__abs () { - var data = this._data; - - this._milliseconds = mathAbs(this._milliseconds); - this._days = mathAbs(this._days); - this._months = mathAbs(this._months); - - data.milliseconds = mathAbs(data.milliseconds); - data.seconds = mathAbs(data.seconds); - data.minutes = mathAbs(data.minutes); - data.hours = mathAbs(data.hours); - data.months = mathAbs(data.months); - data.years = mathAbs(data.years); - - return this; - } - - function duration_add_subtract__addSubtract (duration, input, value, direction) { - var other = create__createDuration(input, value); - - duration._milliseconds += direction * other._milliseconds; - duration._days += direction * other._days; - duration._months += direction * other._months; - - return duration._bubble(); - } - - // supports only 2.0-style add(1, 's') or add(duration) - function duration_add_subtract__add (input, value) { - return duration_add_subtract__addSubtract(this, input, value, 1); - } - - // supports only 2.0-style subtract(1, 's') or subtract(duration) - function duration_add_subtract__subtract (input, value) { - return duration_add_subtract__addSubtract(this, input, value, -1); - } - - function bubble () { - var milliseconds = this._milliseconds; - var days = this._days; - var months = this._months; - var data = this._data; - var seconds, minutes, hours, years = 0; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absFloor(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absFloor(seconds / 60); - data.minutes = minutes % 60; - - hours = absFloor(minutes / 60); - data.hours = hours % 24; - - days += absFloor(hours / 24); - - // Accurately convert days to years, assume start from year 0. - years = absFloor(daysToYears(days)); - days -= absFloor(yearsToDays(years)); - - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absFloor(days / 30); - days %= 30; - - // 12 months -> 1 year - years += absFloor(months / 12); - months %= 12; - - data.days = days; - data.months = months; - data.years = years; - - return this; - } - - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } - - function yearsToDays (years) { - // years * 365 + absFloor(years / 4) - - // absFloor(years / 100) + absFloor(years / 400); - return years * 146097 / 400; - } - - function as (units) { - var days; - var months; - var milliseconds = this._milliseconds; - - units = normalizeUnits(units); - - if (units === 'month' || units === 'year') { - days = this._days + milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(yearsToDays(this._months / 12)); - switch (units) { - case 'week' : return days / 7 + milliseconds / 6048e5; - case 'day' : return days + milliseconds / 864e5; - case 'hour' : return days * 24 + milliseconds / 36e5; - case 'minute' : return days * 1440 + milliseconds / 6e4; - case 'second' : return days * 86400 + milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 864e5) + milliseconds; - default: throw new Error('Unknown unit ' + units); - } - } - } - - // TODO: Use this.as('ms')? - function duration_as__valueOf () { - return ( - this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6 - ); - } - - function makeAs (alias) { - return function () { - return this.as(alias); - }; - } - - var asMilliseconds = makeAs('ms'); - var asSeconds = makeAs('s'); - var asMinutes = makeAs('m'); - var asHours = makeAs('h'); - var asDays = makeAs('d'); - var asWeeks = makeAs('w'); - var asMonths = makeAs('M'); - var asYears = makeAs('y'); - - function duration_get__get (units) { - units = normalizeUnits(units); - return this[units + 's'](); - } - - function makeGetter(name) { - return function () { - return this._data[name]; - }; - } - - var duration_get__milliseconds = makeGetter('milliseconds'); - var seconds = makeGetter('seconds'); - var minutes = makeGetter('minutes'); - var hours = makeGetter('hours'); - var days = makeGetter('days'); - var duration_get__months = makeGetter('months'); - var years = makeGetter('years'); - - function weeks () { - return absFloor(this.days() / 7); - } - - var round = Math.round; - var thresholds = { - s: 45, // seconds to minute - m: 45, // minutes to hour - h: 22, // hours to day - d: 26, // days to month - M: 11 // months to year - }; - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) { - var duration = create__createDuration(posNegDuration).abs(); - var seconds = round(duration.as('s')); - var minutes = round(duration.as('m')); - var hours = round(duration.as('h')); - var days = round(duration.as('d')); - var months = round(duration.as('M')); - var years = round(duration.as('y')); - - var a = seconds < thresholds.s && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < thresholds.m && ['mm', minutes] || - hours === 1 && ['h'] || - hours < thresholds.h && ['hh', hours] || - days === 1 && ['d'] || - days < thresholds.d && ['dd', days] || - months === 1 && ['M'] || - months < thresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; - - a[2] = withoutSuffix; - a[3] = +posNegDuration > 0; - a[4] = locale; - return substituteTimeAgo.apply(null, a); - } - - // This function allows you to set a threshold for relative time strings - function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) { - if (thresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return thresholds[threshold]; - } - thresholds[threshold] = limit; - return true; - } - - function humanize (withSuffix) { - var locale = this.localeData(); - var output = duration_humanize__relativeTime(this, !withSuffix, locale); - - if (withSuffix) { - output = locale.pastFuture(+this, output); - } - - return locale.postformat(output); - } - - var iso_string__abs = Math.abs; - - function iso_string__toISOString() { - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var Y = iso_string__abs(this.years()); - var M = iso_string__abs(this.months()); - var D = iso_string__abs(this.days()); - var h = iso_string__abs(this.hours()); - var m = iso_string__abs(this.minutes()); - var s = iso_string__abs(this.seconds() + this.milliseconds() / 1000); - var total = this.asSeconds(); - - if (!total) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - - return (total < 0 ? '-' : '') + - 'P' + - (Y ? Y + 'Y' : '') + - (M ? M + 'M' : '') + - (D ? D + 'D' : '') + - ((h || m || s) ? 'T' : '') + - (h ? h + 'H' : '') + - (m ? m + 'M' : '') + - (s ? s + 'S' : ''); - } - - var duration_prototype__proto = Duration.prototype; - - duration_prototype__proto.abs = duration_abs__abs; - duration_prototype__proto.add = duration_add_subtract__add; - duration_prototype__proto.subtract = duration_add_subtract__subtract; - duration_prototype__proto.as = as; - duration_prototype__proto.asMilliseconds = asMilliseconds; - duration_prototype__proto.asSeconds = asSeconds; - duration_prototype__proto.asMinutes = asMinutes; - duration_prototype__proto.asHours = asHours; - duration_prototype__proto.asDays = asDays; - duration_prototype__proto.asWeeks = asWeeks; - duration_prototype__proto.asMonths = asMonths; - duration_prototype__proto.asYears = asYears; - duration_prototype__proto.valueOf = duration_as__valueOf; - duration_prototype__proto._bubble = bubble; - duration_prototype__proto.get = duration_get__get; - duration_prototype__proto.milliseconds = duration_get__milliseconds; - duration_prototype__proto.seconds = seconds; - duration_prototype__proto.minutes = minutes; - duration_prototype__proto.hours = hours; - duration_prototype__proto.days = days; - duration_prototype__proto.weeks = weeks; - duration_prototype__proto.months = duration_get__months; - duration_prototype__proto.years = years; - duration_prototype__proto.humanize = humanize; - duration_prototype__proto.toISOString = iso_string__toISOString; - duration_prototype__proto.toString = iso_string__toISOString; - duration_prototype__proto.toJSON = iso_string__toISOString; - duration_prototype__proto.locale = locale; - duration_prototype__proto.localeData = localeData; - - // Deprecations - duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString); - duration_prototype__proto.lang = lang; - - // Side effect imports - - addFormatToken('X', 0, 0, 'unix'); - addFormatToken('x', 0, 0, 'valueOf'); - - // PARSING - - addRegexToken('x', matchSigned); - addRegexToken('X', matchTimestamp); - addParseToken('X', function (input, array, config) { - config._d = new Date(parseFloat(input, 10) * 1000); - }); - addParseToken('x', function (input, array, config) { - config._d = new Date(toInt(input)); - }); - - // Side effect imports - - ; - - //! moment.js - //! version : 2.10.3 - //! authors : Tim Wood, Iskren Chernev, Moment.js contributors - //! license : MIT - //! momentjs.com - - utils_hooks__hooks.version = '2.10.3'; - - setHookCallback(local__createLocal); - - utils_hooks__hooks.fn = momentPrototype; - utils_hooks__hooks.min = min; - utils_hooks__hooks.max = max; - utils_hooks__hooks.utc = create_utc__createUTC; - utils_hooks__hooks.unix = moment_moment__createUnix; - utils_hooks__hooks.months = lists__listMonths; - utils_hooks__hooks.isDate = isDate; - utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale; - utils_hooks__hooks.invalid = valid__createInvalid; - utils_hooks__hooks.duration = create__createDuration; - utils_hooks__hooks.isMoment = isMoment; - utils_hooks__hooks.weekdays = lists__listWeekdays; - utils_hooks__hooks.parseZone = moment_moment__createInZone; - utils_hooks__hooks.localeData = locale_locales__getLocale; - utils_hooks__hooks.isDuration = isDuration; - utils_hooks__hooks.monthsShort = lists__listMonthsShort; - utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin; - utils_hooks__hooks.defineLocale = defineLocale; - utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort; - utils_hooks__hooks.normalizeUnits = normalizeUnits; - utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold; - - var _moment__default = utils_hooks__hooks; - - //! moment.js locale configuration - //! locale : afrikaans (af) - //! author : Werner Mollentze : https://github.com/wernerm - - var af = _moment__default.defineLocale('af', { - months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'), - weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'), - weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'), - weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'), - meridiemParse: /vm|nm/i, - isPM : function (input) { - return /^nm$/i.test(input); - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 12) { - return isLower ? 'vm' : 'VM'; - } else { - return isLower ? 'nm' : 'NM'; - } - }, - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Vandag om] LT', - nextDay : '[Môre om] LT', - nextWeek : 'dddd [om] LT', - lastDay : '[Gister om] LT', - lastWeek : '[Laas] dddd [om] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'oor %s', - past : '%s gelede', - s : '\'n paar sekondes', - m : '\'n minuut', - mm : '%d minute', - h : '\'n uur', - hh : '%d ure', - d : '\'n dag', - dd : '%d dae', - M : '\'n maand', - MM : '%d maande', - y : '\'n jaar', - yy : '%d jaar' - }, - ordinalParse: /\d{1,2}(ste|de)/, - ordinal : function (number) { - return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter - }, - week : { - dow : 1, // Maandag is die eerste dag van die week. - doy : 4 // Die week wat die 4de Januarie bevat is die eerste week van die jaar. - } - }); - - //! moment.js locale configuration - //! locale : Moroccan Arabic (ar-ma) - //! author : ElFadili Yassine : https://github.com/ElFadiliY - //! author : Abdel Said : https://github.com/abdelsaid - - var ar_ma = _moment__default.defineLocale('ar-ma', { - months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'), - monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'), - weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[اليوم على الساعة] LT', - nextDay: '[غدا على الساعة] LT', - nextWeek: 'dddd [على الساعة] LT', - lastDay: '[أمس على الساعة] LT', - lastWeek: 'dddd [على الساعة] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'في %s', - past : 'منذ %s', - s : 'ثوان', - m : 'دقيقة', - mm : '%d دقائق', - h : 'ساعة', - hh : '%d ساعات', - d : 'يوم', - dd : '%d أيام', - M : 'شهر', - MM : '%d أشهر', - y : 'سنة', - yy : '%d سنوات' - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Arabic Saudi Arabia (ar-sa) - //! author : Suhail Alkowaileet : https://github.com/xsoh - - var ar_sa__symbolMap = { - '1': '١', - '2': '٢', - '3': '٣', - '4': '٤', - '5': '٥', - '6': '٦', - '7': '٧', - '8': '٨', - '9': '٩', - '0': '٠' - }, ar_sa__numberMap = { - '١': '1', - '٢': '2', - '٣': '3', - '٤': '4', - '٥': '5', - '٦': '6', - '٧': '7', - '٨': '8', - '٩': '9', - '٠': '0' - }; - - var ar_sa = _moment__default.defineLocale('ar-sa', { - months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'), - monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'), - weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'HH:mm:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - meridiemParse: /ص|م/, - isPM : function (input) { - return 'م' === input; - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'ص'; - } else { - return 'م'; - } - }, - calendar : { - sameDay: '[اليوم على الساعة] LT', - nextDay: '[غدا على الساعة] LT', - nextWeek: 'dddd [على الساعة] LT', - lastDay: '[أمس على الساعة] LT', - lastWeek: 'dddd [على الساعة] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'في %s', - past : 'منذ %s', - s : 'ثوان', - m : 'دقيقة', - mm : '%d دقائق', - h : 'ساعة', - hh : '%d ساعات', - d : 'يوم', - dd : '%d أيام', - M : 'شهر', - MM : '%d أشهر', - y : 'سنة', - yy : '%d سنوات' - }, - preparse: function (string) { - return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) { - return ar_sa__numberMap[match]; - }).replace(/،/g, ','); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return ar_sa__symbolMap[match]; - }).replace(/,/g, '،'); - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Tunisian Arabic (ar-tn) - - var ar_tn = _moment__default.defineLocale('ar-tn', { - months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'), - monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'), - weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat: { - LT: 'HH:mm', - LTS: 'LT:ss', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd D MMMM YYYY LT' - }, - calendar: { - sameDay: '[اليوم على الساعة] LT', - nextDay: '[غدا على الساعة] LT', - nextWeek: 'dddd [على الساعة] LT', - lastDay: '[أمس على الساعة] LT', - lastWeek: 'dddd [على الساعة] LT', - sameElse: 'L' - }, - relativeTime: { - future: 'في %s', - past: 'منذ %s', - s: 'ثوان', - m: 'دقيقة', - mm: '%d دقائق', - h: 'ساعة', - hh: '%d ساعات', - d: 'يوم', - dd: '%d أيام', - M: 'شهر', - MM: '%d أشهر', - y: 'سنة', - yy: '%d سنوات' - }, - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! Locale: Arabic (ar) - //! Author: Abdel Said: https://github.com/abdelsaid - //! Changes in months, weekdays: Ahmed Elkhatib - //! Native plural forms: forabi https://github.com/forabi - - var ar__symbolMap = { - '1': '١', - '2': '٢', - '3': '٣', - '4': '٤', - '5': '٥', - '6': '٦', - '7': '٧', - '8': '٨', - '9': '٩', - '0': '٠' - }, ar__numberMap = { - '١': '1', - '٢': '2', - '٣': '3', - '٤': '4', - '٥': '5', - '٦': '6', - '٧': '7', - '٨': '8', - '٩': '9', - '٠': '0' - }, pluralForm = function (n) { - return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5; - }, plurals = { - s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'], - m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'], - h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'], - d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'], - M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'], - y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام'] - }, pluralize = function (u) { - return function (number, withoutSuffix, string, isFuture) { - var f = pluralForm(number), - str = plurals[u][pluralForm(number)]; - if (f === 2) { - str = str[withoutSuffix ? 0 : 1]; - } - return str.replace(/%d/i, number); - }; - }, ar__months = [ - 'كانون الثاني يناير', - 'شباط فبراير', - 'آذار مارس', - 'نيسان أبريل', - 'أيار مايو', - 'حزيران يونيو', - 'تموز يوليو', - 'آب أغسطس', - 'أيلول سبتمبر', - 'تشرين الأول أكتوبر', - 'تشرين الثاني نوفمبر', - 'كانون الأول ديسمبر' - ]; - - var ar = _moment__default.defineLocale('ar', { - months : ar__months, - monthsShort : ar__months, - weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'HH:mm:ss', - L : 'D/\u200FM/\u200FYYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - meridiemParse: /ص|م/, - isPM : function (input) { - return 'م' === input; - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'ص'; - } else { - return 'م'; - } - }, - calendar : { - sameDay: '[اليوم عند الساعة] LT', - nextDay: '[غدًا عند الساعة] LT', - nextWeek: 'dddd [عند الساعة] LT', - lastDay: '[أمس عند الساعة] LT', - lastWeek: 'dddd [عند الساعة] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'بعد %s', - past : 'منذ %s', - s : pluralize('s'), - m : pluralize('m'), - mm : pluralize('m'), - h : pluralize('h'), - hh : pluralize('h'), - d : pluralize('d'), - dd : pluralize('d'), - M : pluralize('M'), - MM : pluralize('M'), - y : pluralize('y'), - yy : pluralize('y') - }, - preparse: function (string) { - return string.replace(/\u200f/g, '').replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) { - return ar__numberMap[match]; - }).replace(/،/g, ','); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return ar__symbolMap[match]; - }).replace(/,/g, '،'); - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : azerbaijani (az) - //! author : topchiyev : https://github.com/topchiyev - - var az__suffixes = { - 1: '-inci', - 5: '-inci', - 8: '-inci', - 70: '-inci', - 80: '-inci', - 2: '-nci', - 7: '-nci', - 20: '-nci', - 50: '-nci', - 3: '-üncü', - 4: '-üncü', - 100: '-üncü', - 6: '-ncı', - 9: '-uncu', - 10: '-uncu', - 30: '-uncu', - 60: '-ıncı', - 90: '-ıncı' - }; - - var az = _moment__default.defineLocale('az', { - months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'), - monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'), - weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'), - weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'), - weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[bugün saat] LT', - nextDay : '[sabah saat] LT', - nextWeek : '[gələn həftə] dddd [saat] LT', - lastDay : '[dünən] LT', - lastWeek : '[keçən həftə] dddd [saat] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s sonra', - past : '%s əvvəl', - s : 'birneçə saniyyə', - m : 'bir dəqiqə', - mm : '%d dəqiqə', - h : 'bir saat', - hh : '%d saat', - d : 'bir gün', - dd : '%d gün', - M : 'bir ay', - MM : '%d ay', - y : 'bir il', - yy : '%d il' - }, - meridiemParse: /gecə|səhər|gündüz|axşam/, - isPM : function (input) { - return /^(gündüz|axşam)$/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'gecə'; - } else if (hour < 12) { - return 'səhər'; - } else if (hour < 17) { - return 'gündüz'; - } else { - return 'axşam'; - } - }, - ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/, - ordinal : function (number) { - if (number === 0) { // special case for zero - return number + '-ıncı'; - } - var a = number % 10, - b = number % 100 - a, - c = number >= 100 ? 100 : null; - return number + (az__suffixes[a] || az__suffixes[b] || az__suffixes[c]); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : belarusian (be) - //! author : Dmitry Demidov : https://github.com/demidov91 - //! author: Praleska: http://praleska.pro/ - //! Author : Menelion Elensúle : https://github.com/Oire - - function be__plural(word, num) { - var forms = word.split('_'); - return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); - } - function be__relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін', - 'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін', - 'dd': 'дзень_дні_дзён', - 'MM': 'месяц_месяцы_месяцаў', - 'yy': 'год_гады_гадоў' - }; - if (key === 'm') { - return withoutSuffix ? 'хвіліна' : 'хвіліну'; - } - else if (key === 'h') { - return withoutSuffix ? 'гадзіна' : 'гадзіну'; - } - else { - return number + ' ' + be__plural(format[key], +number); - } - } - function be__monthsCaseReplace(m, format) { - var months = { - 'nominative': 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_'), - 'accusative': 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_') - }, - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - return months[nounCase][m.month()]; - } - function be__weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'), - 'accusative': 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_') - }, - nounCase = (/\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/).test(format) ? - 'accusative' : - 'nominative'; - return weekdays[nounCase][m.day()]; - } - - var be = _moment__default.defineLocale('be', { - months : be__monthsCaseReplace, - monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'), - weekdays : be__weekdaysCaseReplace, - weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'), - weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY г.', - LLL : 'D MMMM YYYY г., LT', - LLLL : 'dddd, D MMMM YYYY г., LT' - }, - calendar : { - sameDay: '[Сёння ў] LT', - nextDay: '[Заўтра ў] LT', - lastDay: '[Учора ў] LT', - nextWeek: function () { - return '[У] dddd [ў] LT'; - }, - lastWeek: function () { - switch (this.day()) { - case 0: - case 3: - case 5: - case 6: - return '[У мінулую] dddd [ў] LT'; - case 1: - case 2: - case 4: - return '[У мінулы] dddd [ў] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'праз %s', - past : '%s таму', - s : 'некалькі секунд', - m : be__relativeTimeWithPlural, - mm : be__relativeTimeWithPlural, - h : be__relativeTimeWithPlural, - hh : be__relativeTimeWithPlural, - d : 'дзень', - dd : be__relativeTimeWithPlural, - M : 'месяц', - MM : be__relativeTimeWithPlural, - y : 'год', - yy : be__relativeTimeWithPlural - }, - meridiemParse: /ночы|раніцы|дня|вечара/, - isPM : function (input) { - return /^(дня|вечара)$/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'ночы'; - } else if (hour < 12) { - return 'раніцы'; - } else if (hour < 17) { - return 'дня'; - } else { - return 'вечара'; - } - }, - ordinalParse: /\d{1,2}-(і|ы|га)/, - ordinal: function (number, period) { - switch (period) { - case 'M': - case 'd': - case 'DDD': - case 'w': - case 'W': - return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-і' : number + '-ы'; - case 'D': - return number + '-га'; - default: - return number; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : bulgarian (bg) - //! author : Krasen Borisov : https://github.com/kraz - - var bg = _moment__default.defineLocale('bg', { - months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'), - monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'), - weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'), - weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'), - weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'D.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Днес в] LT', - nextDay : '[Утре в] LT', - nextWeek : 'dddd [в] LT', - lastDay : '[Вчера в] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - case 6: - return '[В изминалата] dddd [в] LT'; - case 1: - case 2: - case 4: - case 5: - return '[В изминалия] dddd [в] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'след %s', - past : 'преди %s', - s : 'няколко секунди', - m : 'минута', - mm : '%d минути', - h : 'час', - hh : '%d часа', - d : 'ден', - dd : '%d дни', - M : 'месец', - MM : '%d месеца', - y : 'година', - yy : '%d години' - }, - ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, - ordinal : function (number) { - var lastDigit = number % 10, - last2Digits = number % 100; - if (number === 0) { - return number + '-ев'; - } else if (last2Digits === 0) { - return number + '-ен'; - } else if (last2Digits > 10 && last2Digits < 20) { - return number + '-ти'; - } else if (lastDigit === 1) { - return number + '-ви'; - } else if (lastDigit === 2) { - return number + '-ри'; - } else if (lastDigit === 7 || lastDigit === 8) { - return number + '-ми'; - } else { - return number + '-ти'; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Bengali (bn) - //! author : Kaushik Gandhi : https://github.com/kaushikgandhi - - var bn__symbolMap = { - '1': '১', - '2': '২', - '3': '৩', - '4': '৪', - '5': '৫', - '6': '৬', - '7': '৭', - '8': '৮', - '9': '৯', - '0': '০' - }, - bn__numberMap = { - '১': '1', - '২': '2', - '৩': '3', - '৪': '4', - '৫': '5', - '৬': '6', - '৭': '7', - '৮': '8', - '৯': '9', - '০': '0' - }; - - var bn = _moment__default.defineLocale('bn', { - months : 'জানুয়ারী_ফেবুয়ারী_মার্চ_এপ্রিল_মে_জুন_জুলাই_অগাস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'), - monthsShort : 'জানু_ফেব_মার্চ_এপর_মে_জুন_জুল_অগ_সেপ্ট_অক্টো_নভ_ডিসেম্'.split('_'), - weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পত্তিবার_শুক্রুবার_শনিবার'.split('_'), - weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পত্তি_শুক্রু_শনি'.split('_'), - weekdaysMin : 'রব_সম_মঙ্গ_বু_ব্রিহ_শু_শনি'.split('_'), - longDateFormat : { - LT : 'A h:mm সময়', - LTS : 'A h:mm:ss সময়', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[আজ] LT', - nextDay : '[আগামীকাল] LT', - nextWeek : 'dddd, LT', - lastDay : '[গতকাল] LT', - lastWeek : '[গত] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s পরে', - past : '%s আগে', - s : 'কএক সেকেন্ড', - m : 'এক মিনিট', - mm : '%d মিনিট', - h : 'এক ঘন্টা', - hh : '%d ঘন্টা', - d : 'এক দিন', - dd : '%d দিন', - M : 'এক মাস', - MM : '%d মাস', - y : 'এক বছর', - yy : '%d বছর' - }, - preparse: function (string) { - return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) { - return bn__numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return bn__symbolMap[match]; - }); - }, - meridiemParse: /রাত|শকাল|দুপুর|বিকেল|রাত/, - isPM: function (input) { - return /^(দুপুর|বিকেল|রাত)$/.test(input); - }, - //Bengali is a vast language its spoken - //in different forms in various parts of the world. - //I have just generalized with most common one used - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'রাত'; - } else if (hour < 10) { - return 'শকাল'; - } else if (hour < 17) { - return 'দুপুর'; - } else if (hour < 20) { - return 'বিকেল'; - } else { - return 'রাত'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : tibetan (bo) - //! author : Thupten N. Chakrishar : https://github.com/vajradog - - var bo__symbolMap = { - '1': '༡', - '2': '༢', - '3': '༣', - '4': '༤', - '5': '༥', - '6': '༦', - '7': '༧', - '8': '༨', - '9': '༩', - '0': '༠' - }, - bo__numberMap = { - '༡': '1', - '༢': '2', - '༣': '3', - '༤': '4', - '༥': '5', - '༦': '6', - '༧': '7', - '༨': '8', - '༩': '9', - '༠': '0' - }; - - var bo = _moment__default.defineLocale('bo', { - months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'), - monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'), - weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'), - weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'), - weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'), - longDateFormat : { - LT : 'A h:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[དི་རིང] LT', - nextDay : '[སང་ཉིན] LT', - nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT', - lastDay : '[ཁ་སང] LT', - lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s ལ་', - past : '%s སྔན་ལ', - s : 'ལམ་སང', - m : 'སྐར་མ་གཅིག', - mm : '%d སྐར་མ', - h : 'ཆུ་ཚོད་གཅིག', - hh : '%d ཆུ་ཚོད', - d : 'ཉིན་གཅིག', - dd : '%d ཉིན་', - M : 'ཟླ་བ་གཅིག', - MM : '%d ཟླ་བ', - y : 'ལོ་གཅིག', - yy : '%d ལོ' - }, - preparse: function (string) { - return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) { - return bo__numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return bo__symbolMap[match]; - }); - }, - meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/, - isPM: function (input) { - return /^(ཉིན་གུང|དགོང་དག|མཚན་མོ)$/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'མཚན་མོ'; - } else if (hour < 10) { - return 'ཞོགས་ཀས'; - } else if (hour < 17) { - return 'ཉིན་གུང'; - } else if (hour < 20) { - return 'དགོང་དག'; - } else { - return 'མཚན་མོ'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : breton (br) - //! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou - - function relativeTimeWithMutation(number, withoutSuffix, key) { - var format = { - 'mm': 'munutenn', - 'MM': 'miz', - 'dd': 'devezh' - }; - return number + ' ' + mutation(format[key], number); - } - function specialMutationForYears(number) { - switch (lastNumber(number)) { - case 1: - case 3: - case 4: - case 5: - case 9: - return number + ' bloaz'; - default: - return number + ' vloaz'; - } - } - function lastNumber(number) { - if (number > 9) { - return lastNumber(number % 10); - } - return number; - } - function mutation(text, number) { - if (number === 2) { - return softMutation(text); - } - return text; - } - function softMutation(text) { - var mutationTable = { - 'm': 'v', - 'b': 'v', - 'd': 'z' - }; - if (mutationTable[text.charAt(0)] === undefined) { - return text; - } - return mutationTable[text.charAt(0)] + text.substring(1); - } - - var br = _moment__default.defineLocale('br', { - months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'), - monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'), - weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'), - weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'), - weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'), - longDateFormat : { - LT : 'h[e]mm A', - LTS : 'h[e]mm:ss A', - L : 'DD/MM/YYYY', - LL : 'D [a viz] MMMM YYYY', - LLL : 'D [a viz] MMMM YYYY LT', - LLLL : 'dddd, D [a viz] MMMM YYYY LT' - }, - calendar : { - sameDay : '[Hiziv da] LT', - nextDay : '[Warc\'hoazh da] LT', - nextWeek : 'dddd [da] LT', - lastDay : '[Dec\'h da] LT', - lastWeek : 'dddd [paset da] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'a-benn %s', - past : '%s \'zo', - s : 'un nebeud segondennoù', - m : 'ur vunutenn', - mm : relativeTimeWithMutation, - h : 'un eur', - hh : '%d eur', - d : 'un devezh', - dd : relativeTimeWithMutation, - M : 'ur miz', - MM : relativeTimeWithMutation, - y : 'ur bloaz', - yy : specialMutationForYears - }, - ordinalParse: /\d{1,2}(añ|vet)/, - ordinal : function (number) { - var output = (number === 1) ? 'añ' : 'vet'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : bosnian (bs) - //! author : Nedim Cholich : https://github.com/frontyard - //! based on (hr) translation by Bojan Marković - - function bs__translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'jedna minuta' : 'jedne minute'; - case 'mm': - if (number === 1) { - result += 'minuta'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'minute'; - } else { - result += 'minuta'; - } - return result; - case 'h': - return withoutSuffix ? 'jedan sat' : 'jednog sata'; - case 'hh': - if (number === 1) { - result += 'sat'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'sata'; - } else { - result += 'sati'; - } - return result; - case 'dd': - if (number === 1) { - result += 'dan'; - } else { - result += 'dana'; - } - return result; - case 'MM': - if (number === 1) { - result += 'mjesec'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'mjeseca'; - } else { - result += 'mjeseci'; - } - return result; - case 'yy': - if (number === 1) { - result += 'godina'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'godine'; - } else { - result += 'godina'; - } - return result; - } - } - - var bs = _moment__default.defineLocale('bs', { - months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'), - monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'), - weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'), - weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), - weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[danas u] LT', - nextDay : '[sutra u] LT', - nextWeek : function () { - switch (this.day()) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[jučer u] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - return '[prošlu] dddd [u] LT'; - case 6: - return '[prošle] [subote] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[prošli] dddd [u] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'prije %s', - s : 'par sekundi', - m : bs__translate, - mm : bs__translate, - h : bs__translate, - hh : bs__translate, - d : 'dan', - dd : bs__translate, - M : 'mjesec', - MM : bs__translate, - y : 'godinu', - yy : bs__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : catalan (ca) - //! author : Juan G. Hurtado : https://github.com/juanghurtado - - var ca = _moment__default.defineLocale('ca', { - months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'), - monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'), - weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'), - weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'), - weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay : function () { - return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - nextDay : function () { - return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - nextWeek : function () { - return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - lastDay : function () { - return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - lastWeek : function () { - return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'en %s', - past : 'fa %s', - s : 'uns segons', - m : 'un minut', - mm : '%d minuts', - h : 'una hora', - hh : '%d hores', - d : 'un dia', - dd : '%d dies', - M : 'un mes', - MM : '%d mesos', - y : 'un any', - yy : '%d anys' - }, - ordinalParse: /\d{1,2}(r|n|t|è|a)/, - ordinal : function (number, period) { - var output = (number === 1) ? 'r' : - (number === 2) ? 'n' : - (number === 3) ? 'r' : - (number === 4) ? 't' : 'è'; - if (period === 'w' || period === 'W') { - output = 'a'; - } - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : czech (cs) - //! author : petrbela : https://github.com/petrbela - - var cs__months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'), - cs__monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_'); - function cs__plural(n) { - return (n > 1) && (n < 5) && (~~(n / 10) !== 1); - } - function cs__translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': // a few seconds / in a few seconds / a few seconds ago - return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami'; - case 'm': // a minute / in a minute / a minute ago - return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou'); - case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago - if (withoutSuffix || isFuture) { - return result + (cs__plural(number) ? 'minuty' : 'minut'); - } else { - return result + 'minutami'; - } - break; - case 'h': // an hour / in an hour / an hour ago - return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou'); - case 'hh': // 9 hours / in 9 hours / 9 hours ago - if (withoutSuffix || isFuture) { - return result + (cs__plural(number) ? 'hodiny' : 'hodin'); - } else { - return result + 'hodinami'; - } - break; - case 'd': // a day / in a day / a day ago - return (withoutSuffix || isFuture) ? 'den' : 'dnem'; - case 'dd': // 9 days / in 9 days / 9 days ago - if (withoutSuffix || isFuture) { - return result + (cs__plural(number) ? 'dny' : 'dní'); - } else { - return result + 'dny'; - } - break; - case 'M': // a month / in a month / a month ago - return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem'; - case 'MM': // 9 months / in 9 months / 9 months ago - if (withoutSuffix || isFuture) { - return result + (cs__plural(number) ? 'měsíce' : 'měsíců'); - } else { - return result + 'měsíci'; - } - break; - case 'y': // a year / in a year / a year ago - return (withoutSuffix || isFuture) ? 'rok' : 'rokem'; - case 'yy': // 9 years / in 9 years / 9 years ago - if (withoutSuffix || isFuture) { - return result + (cs__plural(number) ? 'roky' : 'let'); - } else { - return result + 'lety'; - } - break; - } - } - - var cs = _moment__default.defineLocale('cs', { - months : cs__months, - monthsShort : cs__monthsShort, - monthsParse : (function (months, monthsShort) { - var i, _monthsParse = []; - for (i = 0; i < 12; i++) { - // use custom parser to solve problem with July (červenec) - _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i'); - } - return _monthsParse; - }(cs__months, cs__monthsShort)), - weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'), - weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'), - weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'), - longDateFormat : { - LT: 'H:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[dnes v] LT', - nextDay: '[zítra v] LT', - nextWeek: function () { - switch (this.day()) { - case 0: - return '[v neděli v] LT'; - case 1: - case 2: - return '[v] dddd [v] LT'; - case 3: - return '[ve středu v] LT'; - case 4: - return '[ve čtvrtek v] LT'; - case 5: - return '[v pátek v] LT'; - case 6: - return '[v sobotu v] LT'; - } - }, - lastDay: '[včera v] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[minulou neděli v] LT'; - case 1: - case 2: - return '[minulé] dddd [v] LT'; - case 3: - return '[minulou středu v] LT'; - case 4: - case 5: - return '[minulý] dddd [v] LT'; - case 6: - return '[minulou sobotu v] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'za %s', - past : 'před %s', - s : cs__translate, - m : cs__translate, - mm : cs__translate, - h : cs__translate, - hh : cs__translate, - d : cs__translate, - dd : cs__translate, - M : cs__translate, - MM : cs__translate, - y : cs__translate, - yy : cs__translate - }, - ordinalParse : /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : chuvash (cv) - //! author : Anatoly Mironov : https://github.com/mirontoli - - var cv = _moment__default.defineLocale('cv', { - months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'), - monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'), - weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'), - weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'), - weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD-MM-YYYY', - LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]', - LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], LT', - LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], LT' - }, - calendar : { - sameDay: '[Паян] LT [сехетре]', - nextDay: '[Ыран] LT [сехетре]', - lastDay: '[Ӗнер] LT [сехетре]', - nextWeek: '[Ҫитес] dddd LT [сехетре]', - lastWeek: '[Иртнӗ] dddd LT [сехетре]', - sameElse: 'L' - }, - relativeTime : { - future : function (output) { - var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран'; - return output + affix; - }, - past : '%s каялла', - s : 'пӗр-ик ҫеккунт', - m : 'пӗр минут', - mm : '%d минут', - h : 'пӗр сехет', - hh : '%d сехет', - d : 'пӗр кун', - dd : '%d кун', - M : 'пӗр уйӑх', - MM : '%d уйӑх', - y : 'пӗр ҫул', - yy : '%d ҫул' - }, - ordinalParse: /\d{1,2}-мӗш/, - ordinal : '%d-мӗш', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Welsh (cy) - //! author : Robert Allen - - var cy = _moment__default.defineLocale('cy', { - months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'), - monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'), - weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'), - weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'), - weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'), - // time formats are the same as en-gb - longDateFormat: { - LT: 'HH:mm', - LTS : 'LT:ss', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd, D MMMM YYYY LT' - }, - calendar: { - sameDay: '[Heddiw am] LT', - nextDay: '[Yfory am] LT', - nextWeek: 'dddd [am] LT', - lastDay: '[Ddoe am] LT', - lastWeek: 'dddd [diwethaf am] LT', - sameElse: 'L' - }, - relativeTime: { - future: 'mewn %s', - past: '%s yn ôl', - s: 'ychydig eiliadau', - m: 'munud', - mm: '%d munud', - h: 'awr', - hh: '%d awr', - d: 'diwrnod', - dd: '%d diwrnod', - M: 'mis', - MM: '%d mis', - y: 'blwyddyn', - yy: '%d flynedd' - }, - ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/, - // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh - ordinal: function (number) { - var b = number, - output = '', - lookup = [ - '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed - 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed - ]; - if (b > 20) { - if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) { - output = 'fed'; // not 30ain, 70ain or 90ain - } else { - output = 'ain'; - } - } else if (b > 0) { - output = lookup[b]; - } - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : danish (da) - //! author : Ulrik Nielsen : https://github.com/mrbase - - var da = _moment__default.defineLocale('da', { - months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), - weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), - weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'), - weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd [d.] D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[I dag kl.] LT', - nextDay : '[I morgen kl.] LT', - nextWeek : 'dddd [kl.] LT', - lastDay : '[I går kl.] LT', - lastWeek : '[sidste] dddd [kl] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'om %s', - past : '%s siden', - s : 'få sekunder', - m : 'et minut', - mm : '%d minutter', - h : 'en time', - hh : '%d timer', - d : 'en dag', - dd : '%d dage', - M : 'en måned', - MM : '%d måneder', - y : 'et år', - yy : '%d år' - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : austrian german (de-at) - //! author : lluchs : https://github.com/lluchs - //! author: Menelion Elensúle: https://github.com/Oire - //! author : Martin Groller : https://github.com/MadMG - - function de_at__processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 'm': ['eine Minute', 'einer Minute'], - 'h': ['eine Stunde', 'einer Stunde'], - 'd': ['ein Tag', 'einem Tag'], - 'dd': [number + ' Tage', number + ' Tagen'], - 'M': ['ein Monat', 'einem Monat'], - 'MM': [number + ' Monate', number + ' Monaten'], - 'y': ['ein Jahr', 'einem Jahr'], - 'yy': [number + ' Jahre', number + ' Jahren'] - }; - return withoutSuffix ? format[key][0] : format[key][1]; - } - - var de_at = _moment__default.defineLocale('de-at', { - months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), - monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'), - weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'), - weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), - weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), - longDateFormat : { - LT: 'HH:mm', - LTS: 'HH:mm:ss', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[Heute um] LT [Uhr]', - sameElse: 'L', - nextDay: '[Morgen um] LT [Uhr]', - nextWeek: 'dddd [um] LT [Uhr]', - lastDay: '[Gestern um] LT [Uhr]', - lastWeek: '[letzten] dddd [um] LT [Uhr]' - }, - relativeTime : { - future : 'in %s', - past : 'vor %s', - s : 'ein paar Sekunden', - m : de_at__processRelativeTime, - mm : '%d Minuten', - h : de_at__processRelativeTime, - hh : '%d Stunden', - d : de_at__processRelativeTime, - dd : de_at__processRelativeTime, - M : de_at__processRelativeTime, - MM : de_at__processRelativeTime, - y : de_at__processRelativeTime, - yy : de_at__processRelativeTime - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : german (de) - //! author : lluchs : https://github.com/lluchs - //! author: Menelion Elensúle: https://github.com/Oire - - function de__processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 'm': ['eine Minute', 'einer Minute'], - 'h': ['eine Stunde', 'einer Stunde'], - 'd': ['ein Tag', 'einem Tag'], - 'dd': [number + ' Tage', number + ' Tagen'], - 'M': ['ein Monat', 'einem Monat'], - 'MM': [number + ' Monate', number + ' Monaten'], - 'y': ['ein Jahr', 'einem Jahr'], - 'yy': [number + ' Jahre', number + ' Jahren'] - }; - return withoutSuffix ? format[key][0] : format[key][1]; - } - - var de = _moment__default.defineLocale('de', { - months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), - monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'), - weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'), - weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), - weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), - longDateFormat : { - LT: 'HH:mm', - LTS: 'HH:mm:ss', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[Heute um] LT [Uhr]', - sameElse: 'L', - nextDay: '[Morgen um] LT [Uhr]', - nextWeek: 'dddd [um] LT [Uhr]', - lastDay: '[Gestern um] LT [Uhr]', - lastWeek: '[letzten] dddd [um] LT [Uhr]' - }, - relativeTime : { - future : 'in %s', - past : 'vor %s', - s : 'ein paar Sekunden', - m : de__processRelativeTime, - mm : '%d Minuten', - h : de__processRelativeTime, - hh : '%d Stunden', - d : de__processRelativeTime, - dd : de__processRelativeTime, - M : de__processRelativeTime, - MM : de__processRelativeTime, - y : de__processRelativeTime, - yy : de__processRelativeTime - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : modern greek (el) - //! author : Aggelos Karalias : https://github.com/mehiel - - var el = _moment__default.defineLocale('el', { - monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'), - monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'), - months : function (momentToFormat, format) { - if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM' - return this._monthsGenitiveEl[momentToFormat.month()]; - } else { - return this._monthsNominativeEl[momentToFormat.month()]; - } - }, - monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'), - weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'), - weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'), - weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'), - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'μμ' : 'ΜΜ'; - } else { - return isLower ? 'πμ' : 'ΠΜ'; - } - }, - isPM : function (input) { - return ((input + '').toLowerCase()[0] === 'μ'); - }, - meridiemParse : /[ΠΜ]\.?Μ?\.?/i, - longDateFormat : { - LT : 'h:mm A', - LTS : 'h:mm:ss A', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendarEl : { - sameDay : '[Σήμερα {}] LT', - nextDay : '[Αύριο {}] LT', - nextWeek : 'dddd [{}] LT', - lastDay : '[Χθες {}] LT', - lastWeek : function () { - switch (this.day()) { - case 6: - return '[το προηγούμενο] dddd [{}] LT'; - default: - return '[την προηγούμενη] dddd [{}] LT'; - } - }, - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendarEl[key], - hours = mom && mom.hours(); - if (typeof output === 'function') { - output = output.apply(mom); - } - return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις')); - }, - relativeTime : { - future : 'σε %s', - past : '%s πριν', - s : 'λίγα δευτερόλεπτα', - m : 'ένα λεπτό', - mm : '%d λεπτά', - h : 'μία ώρα', - hh : '%d ώρες', - d : 'μία μέρα', - dd : '%d μέρες', - M : 'ένας μήνας', - MM : '%d μήνες', - y : 'ένας χρόνος', - yy : '%d χρόνια' - }, - ordinalParse: /\d{1,2}η/, - ordinal: '%dη', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : australian english (en-au) - - var en_au = _moment__default.defineLocale('en-au', { - months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - longDateFormat : { - LT : 'h:mm A', - LTS : 'h:mm:ss A', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - ordinalParse: /\d{1,2}(st|nd|rd|th)/, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : canadian english (en-ca) - //! author : Jonathan Abourbih : https://github.com/jonbca - - var en_ca = _moment__default.defineLocale('en-ca', { - months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - longDateFormat : { - LT : 'h:mm A', - LTS : 'h:mm:ss A', - L : 'YYYY-MM-DD', - LL : 'D MMMM, YYYY', - LLL : 'D MMMM, YYYY LT', - LLLL : 'dddd, D MMMM, YYYY LT' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - ordinalParse: /\d{1,2}(st|nd|rd|th)/, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - //! moment.js locale configuration - //! locale : great britain english (en-gb) - //! author : Chris Gedrim : https://github.com/chrisgedrim - - var en_gb = _moment__default.defineLocale('en-gb', { - months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'HH:mm:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - ordinalParse: /\d{1,2}(st|nd|rd|th)/, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : esperanto (eo) - //! author : Colin Dean : https://github.com/colindean - //! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko. - //! Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni! - - var eo = _moment__default.defineLocale('eo', { - months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec'.split('_'), - weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'), - weekdaysShort : 'Dim_Lun_Mard_Merk_Ĵaŭ_Ven_Sab'.split('_'), - weekdaysMin : 'Di_Lu_Ma_Me_Ĵa_Ve_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'YYYY-MM-DD', - LL : 'D[-an de] MMMM, YYYY', - LLL : 'D[-an de] MMMM, YYYY LT', - LLLL : 'dddd, [la] D[-an de] MMMM, YYYY LT' - }, - meridiemParse: /[ap]\.t\.m/i, - isPM: function (input) { - return input.charAt(0).toLowerCase() === 'p'; - }, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'p.t.m.' : 'P.T.M.'; - } else { - return isLower ? 'a.t.m.' : 'A.T.M.'; - } - }, - calendar : { - sameDay : '[Hodiaŭ je] LT', - nextDay : '[Morgaŭ je] LT', - nextWeek : 'dddd [je] LT', - lastDay : '[Hieraŭ je] LT', - lastWeek : '[pasinta] dddd [je] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'je %s', - past : 'antaŭ %s', - s : 'sekundoj', - m : 'minuto', - mm : '%d minutoj', - h : 'horo', - hh : '%d horoj', - d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo - dd : '%d tagoj', - M : 'monato', - MM : '%d monatoj', - y : 'jaro', - yy : '%d jaroj' - }, - ordinalParse: /\d{1,2}a/, - ordinal : '%da', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : spanish (es) - //! author : Julio Napurí : https://github.com/julionc - - var monthsShortDot = 'Ene._Feb._Mar._Abr._May._Jun._Jul._Ago._Sep._Oct._Nov._Dic.'.split('_'), - es__monthsShort = 'Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Sep_Oct_Nov_Dic'.split('_'); - - var es = _moment__default.defineLocale('es', { - months : 'Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre'.split('_'), - monthsShort : function (m, format) { - if (/-MMM-/.test(format)) { - return es__monthsShort[m.month()]; - } else { - return monthsShortDot[m.month()]; - } - }, - weekdays : 'Domingo_Lunes_Martes_Miércoles_Jueves_Viernes_Sábado'.split('_'), - weekdaysShort : 'Dom._Lun._Mar._Mié._Jue._Vie._Sáb.'.split('_'), - weekdaysMin : 'Do_Lu_Ma_Mi_Ju_Vi_Sá'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D [de] MMMM [de] YYYY', - LLL : 'D [de] MMMM [de] YYYY LT', - LLLL : 'dddd, D [de] MMMM [de] YYYY LT' - }, - calendar : { - sameDay : function () { - return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - nextDay : function () { - return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - nextWeek : function () { - return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - lastDay : function () { - return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - lastWeek : function () { - return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'en %s', - past : 'hace %s', - s : 'unos segundos', - m : 'un minuto', - mm : '%d minutos', - h : 'una hora', - hh : '%d horas', - d : 'un día', - dd : '%d días', - M : 'un mes', - MM : '%d meses', - y : 'un año', - yy : '%d años' - }, - ordinalParse : /\d{1,2}º/, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : estonian (et) - //! author : Henry Kehlmann : https://github.com/madhenry - //! improvements : Illimar Tambek : https://github.com/ragulka - - function et__processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'], - 'm' : ['ühe minuti', 'üks minut'], - 'mm': [number + ' minuti', number + ' minutit'], - 'h' : ['ühe tunni', 'tund aega', 'üks tund'], - 'hh': [number + ' tunni', number + ' tundi'], - 'd' : ['ühe päeva', 'üks päev'], - 'M' : ['kuu aja', 'kuu aega', 'üks kuu'], - 'MM': [number + ' kuu', number + ' kuud'], - 'y' : ['ühe aasta', 'aasta', 'üks aasta'], - 'yy': [number + ' aasta', number + ' aastat'] - }; - if (withoutSuffix) { - return format[key][2] ? format[key][2] : format[key][1]; - } - return isFuture ? format[key][0] : format[key][1]; - } - - var et = _moment__default.defineLocale('et', { - months : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'), - monthsShort : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'), - weekdays : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'), - weekdaysShort : 'P_E_T_K_N_R_L'.split('_'), - weekdaysMin : 'P_E_T_K_N_R_L'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[Täna,] LT', - nextDay : '[Homme,] LT', - nextWeek : '[Järgmine] dddd LT', - lastDay : '[Eile,] LT', - lastWeek : '[Eelmine] dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s pärast', - past : '%s tagasi', - s : et__processRelativeTime, - m : et__processRelativeTime, - mm : et__processRelativeTime, - h : et__processRelativeTime, - hh : et__processRelativeTime, - d : et__processRelativeTime, - dd : '%d päeva', - M : et__processRelativeTime, - MM : et__processRelativeTime, - y : et__processRelativeTime, - yy : et__processRelativeTime - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : euskara (eu) - //! author : Eneko Illarramendi : https://github.com/eillarra - - var eu = _moment__default.defineLocale('eu', { - months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'), - monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'), - weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'), - weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'), - weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'YYYY-MM-DD', - LL : 'YYYY[ko] MMMM[ren] D[a]', - LLL : 'YYYY[ko] MMMM[ren] D[a] LT', - LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] LT', - l : 'YYYY-M-D', - ll : 'YYYY[ko] MMM D[a]', - lll : 'YYYY[ko] MMM D[a] LT', - llll : 'ddd, YYYY[ko] MMM D[a] LT' - }, - calendar : { - sameDay : '[gaur] LT[etan]', - nextDay : '[bihar] LT[etan]', - nextWeek : 'dddd LT[etan]', - lastDay : '[atzo] LT[etan]', - lastWeek : '[aurreko] dddd LT[etan]', - sameElse : 'L' - }, - relativeTime : { - future : '%s barru', - past : 'duela %s', - s : 'segundo batzuk', - m : 'minutu bat', - mm : '%d minutu', - h : 'ordu bat', - hh : '%d ordu', - d : 'egun bat', - dd : '%d egun', - M : 'hilabete bat', - MM : '%d hilabete', - y : 'urte bat', - yy : '%d urte' - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Persian (fa) - //! author : Ebrahim Byagowi : https://github.com/ebraminio - - var fa__symbolMap = { - '1': '۱', - '2': '۲', - '3': '۳', - '4': '۴', - '5': '۵', - '6': '۶', - '7': '۷', - '8': '۸', - '9': '۹', - '0': '۰' - }, fa__numberMap = { - '۱': '1', - '۲': '2', - '۳': '3', - '۴': '4', - '۵': '5', - '۶': '6', - '۷': '7', - '۸': '8', - '۹': '9', - '۰': '0' - }; - - var fa = _moment__default.defineLocale('fa', { - months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'), - monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'), - weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'), - weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'), - weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - meridiemParse: /قبل از ظهر|بعد از ظهر/, - isPM: function (input) { - return /بعد از ظهر/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'قبل از ظهر'; - } else { - return 'بعد از ظهر'; - } - }, - calendar : { - sameDay : '[امروز ساعت] LT', - nextDay : '[فردا ساعت] LT', - nextWeek : 'dddd [ساعت] LT', - lastDay : '[دیروز ساعت] LT', - lastWeek : 'dddd [پیش] [ساعت] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'در %s', - past : '%s پیش', - s : 'چندین ثانیه', - m : 'یک دقیقه', - mm : '%d دقیقه', - h : 'یک ساعت', - hh : '%d ساعت', - d : 'یک روز', - dd : '%d روز', - M : 'یک ماه', - MM : '%d ماه', - y : 'یک سال', - yy : '%d سال' - }, - preparse: function (string) { - return string.replace(/[۰-۹]/g, function (match) { - return fa__numberMap[match]; - }).replace(/،/g, ','); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return fa__symbolMap[match]; - }).replace(/,/g, '،'); - }, - ordinalParse: /\d{1,2}م/, - ordinal : '%dم', - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : finnish (fi) - //! author : Tarmo Aidantausta : https://github.com/bleadof - - var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' '), - numbersFuture = [ - 'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden', - numbersPast[7], numbersPast[8], numbersPast[9] - ]; - function fi__translate(number, withoutSuffix, key, isFuture) { - var result = ''; - switch (key) { - case 's': - return isFuture ? 'muutaman sekunnin' : 'muutama sekunti'; - case 'm': - return isFuture ? 'minuutin' : 'minuutti'; - case 'mm': - result = isFuture ? 'minuutin' : 'minuuttia'; - break; - case 'h': - return isFuture ? 'tunnin' : 'tunti'; - case 'hh': - result = isFuture ? 'tunnin' : 'tuntia'; - break; - case 'd': - return isFuture ? 'päivän' : 'päivä'; - case 'dd': - result = isFuture ? 'päivän' : 'päivää'; - break; - case 'M': - return isFuture ? 'kuukauden' : 'kuukausi'; - case 'MM': - result = isFuture ? 'kuukauden' : 'kuukautta'; - break; - case 'y': - return isFuture ? 'vuoden' : 'vuosi'; - case 'yy': - result = isFuture ? 'vuoden' : 'vuotta'; - break; - } - result = verbalNumber(number, isFuture) + ' ' + result; - return result; - } - function verbalNumber(number, isFuture) { - return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number; - } - - var fi = _moment__default.defineLocale('fi', { - months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'), - monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'), - weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'), - weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'), - weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'), - longDateFormat : { - LT : 'HH.mm', - LTS : 'HH.mm.ss', - L : 'DD.MM.YYYY', - LL : 'Do MMMM[ta] YYYY', - LLL : 'Do MMMM[ta] YYYY, [klo] LT', - LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] LT', - l : 'D.M.YYYY', - ll : 'Do MMM YYYY', - lll : 'Do MMM YYYY, [klo] LT', - llll : 'ddd, Do MMM YYYY, [klo] LT' - }, - calendar : { - sameDay : '[tänään] [klo] LT', - nextDay : '[huomenna] [klo] LT', - nextWeek : 'dddd [klo] LT', - lastDay : '[eilen] [klo] LT', - lastWeek : '[viime] dddd[na] [klo] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s päästä', - past : '%s sitten', - s : fi__translate, - m : fi__translate, - mm : fi__translate, - h : fi__translate, - hh : fi__translate, - d : fi__translate, - dd : fi__translate, - M : fi__translate, - MM : fi__translate, - y : fi__translate, - yy : fi__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : faroese (fo) - //! author : Ragnar Johannesen : https://github.com/ragnar123 - - var fo = _moment__default.defineLocale('fo', { - months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), - weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'), - weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'), - weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D. MMMM, YYYY LT' - }, - calendar : { - sameDay : '[Í dag kl.] LT', - nextDay : '[Í morgin kl.] LT', - nextWeek : 'dddd [kl.] LT', - lastDay : '[Í gjár kl.] LT', - lastWeek : '[síðstu] dddd [kl] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'um %s', - past : '%s síðani', - s : 'fá sekund', - m : 'ein minutt', - mm : '%d minuttir', - h : 'ein tími', - hh : '%d tímar', - d : 'ein dagur', - dd : '%d dagar', - M : 'ein mánaði', - MM : '%d mánaðir', - y : 'eitt ár', - yy : '%d ár' - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : canadian french (fr-ca) - //! author : Jonathan Abourbih : https://github.com/jonbca - - var fr_ca = _moment__default.defineLocale('fr-ca', { - months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), - monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), - weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), - weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), - weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'YYYY-MM-DD', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Aujourd\'hui à] LT', - nextDay: '[Demain à] LT', - nextWeek: 'dddd [à] LT', - lastDay: '[Hier à] LT', - lastWeek: 'dddd [dernier à] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'dans %s', - past : 'il y a %s', - s : 'quelques secondes', - m : 'une minute', - mm : '%d minutes', - h : 'une heure', - hh : '%d heures', - d : 'un jour', - dd : '%d jours', - M : 'un mois', - MM : '%d mois', - y : 'un an', - yy : '%d ans' - }, - ordinalParse: /\d{1,2}(er|)/, - ordinal : function (number) { - return number + (number === 1 ? 'er' : ''); - } - }); - - //! moment.js locale configuration - //! locale : french (fr) - //! author : John Fischer : https://github.com/jfroffice - - var fr = _moment__default.defineLocale('fr', { - months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), - monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), - weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), - weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), - weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Aujourd\'hui à] LT', - nextDay: '[Demain à] LT', - nextWeek: 'dddd [à] LT', - lastDay: '[Hier à] LT', - lastWeek: 'dddd [dernier à] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'dans %s', - past : 'il y a %s', - s : 'quelques secondes', - m : 'une minute', - mm : '%d minutes', - h : 'une heure', - hh : '%d heures', - d : 'un jour', - dd : '%d jours', - M : 'un mois', - MM : '%d mois', - y : 'un an', - yy : '%d ans' - }, - ordinalParse: /\d{1,2}(er|)/, - ordinal : function (number) { - return number + (number === 1 ? 'er' : ''); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : frisian (fy) - //! author : Robin van der Vliet : https://github.com/robin0van0der0v - - var fy__monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_'), - fy__monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'); - - var fy = _moment__default.defineLocale('fy', { - months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'), - monthsShort : function (m, format) { - if (/-MMM-/.test(format)) { - return fy__monthsShortWithoutDots[m.month()]; - } else { - return fy__monthsShortWithDots[m.month()]; - } - }, - weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'), - weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'), - weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD-MM-YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[hjoed om] LT', - nextDay: '[moarn om] LT', - nextWeek: 'dddd [om] LT', - lastDay: '[juster om] LT', - lastWeek: '[ôfrûne] dddd [om] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'oer %s', - past : '%s lyn', - s : 'in pear sekonden', - m : 'ien minút', - mm : '%d minuten', - h : 'ien oere', - hh : '%d oeren', - d : 'ien dei', - dd : '%d dagen', - M : 'ien moanne', - MM : '%d moannen', - y : 'ien jier', - yy : '%d jierren' - }, - ordinalParse: /\d{1,2}(ste|de)/, - ordinal : function (number) { - return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : galician (gl) - //! author : Juan G. Hurtado : https://github.com/juanghurtado - - var gl = _moment__default.defineLocale('gl', { - months : 'Xaneiro_Febreiro_Marzo_Abril_Maio_Xuño_Xullo_Agosto_Setembro_Outubro_Novembro_Decembro'.split('_'), - monthsShort : 'Xan._Feb._Mar._Abr._Mai._Xuñ._Xul._Ago._Set._Out._Nov._Dec.'.split('_'), - weekdays : 'Domingo_Luns_Martes_Mércores_Xoves_Venres_Sábado'.split('_'), - weekdaysShort : 'Dom._Lun._Mar._Mér._Xov._Ven._Sáb.'.split('_'), - weekdaysMin : 'Do_Lu_Ma_Mé_Xo_Ve_Sá'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay : function () { - return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT'; - }, - nextDay : function () { - return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT'; - }, - nextWeek : function () { - return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT'; - }, - lastDay : function () { - return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT'; - }, - lastWeek : function () { - return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT'; - }, - sameElse : 'L' - }, - relativeTime : { - future : function (str) { - if (str === 'uns segundos') { - return 'nuns segundos'; - } - return 'en ' + str; - }, - past : 'hai %s', - s : 'uns segundos', - m : 'un minuto', - mm : '%d minutos', - h : 'unha hora', - hh : '%d horas', - d : 'un día', - dd : '%d días', - M : 'un mes', - MM : '%d meses', - y : 'un ano', - yy : '%d anos' - }, - ordinalParse : /\d{1,2}º/, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Hebrew (he) - //! author : Tomer Cohen : https://github.com/tomer - //! author : Moshe Simantov : https://github.com/DevelopmentIL - //! author : Tal Ater : https://github.com/TalAter - - var he = _moment__default.defineLocale('he', { - months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'), - monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'), - weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'), - weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'), - weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D [ב]MMMM YYYY', - LLL : 'D [ב]MMMM YYYY LT', - LLLL : 'dddd, D [ב]MMMM YYYY LT', - l : 'D/M/YYYY', - ll : 'D MMM YYYY', - lll : 'D MMM YYYY LT', - llll : 'ddd, D MMM YYYY LT' - }, - calendar : { - sameDay : '[היום ב־]LT', - nextDay : '[מחר ב־]LT', - nextWeek : 'dddd [בשעה] LT', - lastDay : '[אתמול ב־]LT', - lastWeek : '[ביום] dddd [האחרון בשעה] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'בעוד %s', - past : 'לפני %s', - s : 'מספר שניות', - m : 'דקה', - mm : '%d דקות', - h : 'שעה', - hh : function (number) { - if (number === 2) { - return 'שעתיים'; - } - return number + ' שעות'; - }, - d : 'יום', - dd : function (number) { - if (number === 2) { - return 'יומיים'; - } - return number + ' ימים'; - }, - M : 'חודש', - MM : function (number) { - if (number === 2) { - return 'חודשיים'; - } - return number + ' חודשים'; - }, - y : 'שנה', - yy : function (number) { - if (number === 2) { - return 'שנתיים'; - } else if (number % 10 === 0 && number !== 10) { - return number + ' שנה'; - } - return number + ' שנים'; - } - } - }); - - //! moment.js locale configuration - //! locale : hindi (hi) - //! author : Mayank Singhal : https://github.com/mayanksinghal - - var hi__symbolMap = { - '1': '१', - '2': '२', - '3': '३', - '4': '४', - '5': '५', - '6': '६', - '7': '७', - '8': '८', - '9': '९', - '0': '०' - }, - hi__numberMap = { - '१': '1', - '२': '2', - '३': '3', - '४': '4', - '५': '5', - '६': '6', - '७': '7', - '८': '8', - '९': '9', - '०': '0' - }; - - var hi = _moment__default.defineLocale('hi', { - months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'), - monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'), - weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'), - weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'), - weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'), - longDateFormat : { - LT : 'A h:mm बजे', - LTS : 'A h:mm:ss बजे', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[आज] LT', - nextDay : '[कल] LT', - nextWeek : 'dddd, LT', - lastDay : '[कल] LT', - lastWeek : '[पिछले] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s में', - past : '%s पहले', - s : 'कुछ ही क्षण', - m : 'एक मिनट', - mm : '%d मिनट', - h : 'एक घंटा', - hh : '%d घंटे', - d : 'एक दिन', - dd : '%d दिन', - M : 'एक महीने', - MM : '%d महीने', - y : 'एक वर्ष', - yy : '%d वर्ष' - }, - preparse: function (string) { - return string.replace(/[१२३४५६७८९०]/g, function (match) { - return hi__numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return hi__symbolMap[match]; - }); - }, - // Hindi notation for meridiems are quite fuzzy in practice. While there exists - // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi. - meridiemParse: /रात|सुबह|दोपहर|शाम/, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'रात') { - return hour < 4 ? hour : hour + 12; - } else if (meridiem === 'सुबह') { - return hour; - } else if (meridiem === 'दोपहर') { - return hour >= 10 ? hour : hour + 12; - } else if (meridiem === 'शाम') { - return hour + 12; - } - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'रात'; - } else if (hour < 10) { - return 'सुबह'; - } else if (hour < 17) { - return 'दोपहर'; - } else if (hour < 20) { - return 'शाम'; - } else { - return 'रात'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : hrvatski (hr) - //! author : Bojan Marković : https://github.com/bmarkovic - - function hr__translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'jedna minuta' : 'jedne minute'; - case 'mm': - if (number === 1) { - result += 'minuta'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'minute'; - } else { - result += 'minuta'; - } - return result; - case 'h': - return withoutSuffix ? 'jedan sat' : 'jednog sata'; - case 'hh': - if (number === 1) { - result += 'sat'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'sata'; - } else { - result += 'sati'; - } - return result; - case 'dd': - if (number === 1) { - result += 'dan'; - } else { - result += 'dana'; - } - return result; - case 'MM': - if (number === 1) { - result += 'mjesec'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'mjeseca'; - } else { - result += 'mjeseci'; - } - return result; - case 'yy': - if (number === 1) { - result += 'godina'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'godine'; - } else { - result += 'godina'; - } - return result; - } - } - - var hr = _moment__default.defineLocale('hr', { - months : 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_'), - monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'), - weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'), - weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), - weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[danas u] LT', - nextDay : '[sutra u] LT', - nextWeek : function () { - switch (this.day()) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[jučer u] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - return '[prošlu] dddd [u] LT'; - case 6: - return '[prošle] [subote] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[prošli] dddd [u] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'prije %s', - s : 'par sekundi', - m : hr__translate, - mm : hr__translate, - h : hr__translate, - hh : hr__translate, - d : 'dan', - dd : hr__translate, - M : 'mjesec', - MM : hr__translate, - y : 'godinu', - yy : hr__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : hungarian (hu) - //! author : Adam Brunner : https://github.com/adambrunner - - var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' '); - function hu__translate(number, withoutSuffix, key, isFuture) { - var num = number, - suffix; - switch (key) { - case 's': - return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce'; - case 'm': - return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce'); - case 'mm': - return num + (isFuture || withoutSuffix ? ' perc' : ' perce'); - case 'h': - return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája'); - case 'hh': - return num + (isFuture || withoutSuffix ? ' óra' : ' órája'); - case 'd': - return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja'); - case 'dd': - return num + (isFuture || withoutSuffix ? ' nap' : ' napja'); - case 'M': - return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja'); - case 'MM': - return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja'); - case 'y': - return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve'); - case 'yy': - return num + (isFuture || withoutSuffix ? ' év' : ' éve'); - } - return ''; - } - function week(isFuture) { - return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]'; - } - - var hu = _moment__default.defineLocale('hu', { - months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'), - monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'), - weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'), - weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'), - weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'YYYY.MM.DD.', - LL : 'YYYY. MMMM D.', - LLL : 'YYYY. MMMM D., LT', - LLLL : 'YYYY. MMMM D., dddd LT' - }, - meridiemParse: /de|du/i, - isPM: function (input) { - return input.charAt(1).toLowerCase() === 'u'; - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 12) { - return isLower === true ? 'de' : 'DE'; - } else { - return isLower === true ? 'du' : 'DU'; - } - }, - calendar : { - sameDay : '[ma] LT[-kor]', - nextDay : '[holnap] LT[-kor]', - nextWeek : function () { - return week.call(this, true); - }, - lastDay : '[tegnap] LT[-kor]', - lastWeek : function () { - return week.call(this, false); - }, - sameElse : 'L' - }, - relativeTime : { - future : '%s múlva', - past : '%s', - s : hu__translate, - m : hu__translate, - mm : hu__translate, - h : hu__translate, - hh : hu__translate, - d : hu__translate, - dd : hu__translate, - M : hu__translate, - MM : hu__translate, - y : hu__translate, - yy : hu__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Armenian (hy-am) - //! author : Armendarabyan : https://github.com/armendarabyan - - function hy_am__monthsCaseReplace(m, format) { - var months = { - 'nominative': 'հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր'.split('_'), - 'accusative': 'հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի'.split('_') - }, - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - return months[nounCase][m.month()]; - } - function hy_am__monthsShortCaseReplace(m, format) { - var monthsShort = 'հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ'.split('_'); - return monthsShort[m.month()]; - } - function hy_am__weekdaysCaseReplace(m, format) { - var weekdays = 'կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ'.split('_'); - return weekdays[m.day()]; - } - - var hy_am = _moment__default.defineLocale('hy-am', { - months : hy_am__monthsCaseReplace, - monthsShort : hy_am__monthsShortCaseReplace, - weekdays : hy_am__weekdaysCaseReplace, - weekdaysShort : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'), - weekdaysMin : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY թ.', - LLL : 'D MMMM YYYY թ., LT', - LLLL : 'dddd, D MMMM YYYY թ., LT' - }, - calendar : { - sameDay: '[այսօր] LT', - nextDay: '[վաղը] LT', - lastDay: '[երեկ] LT', - nextWeek: function () { - return 'dddd [օրը ժամը] LT'; - }, - lastWeek: function () { - return '[անցած] dddd [օրը ժամը] LT'; - }, - sameElse: 'L' - }, - relativeTime : { - future : '%s հետո', - past : '%s առաջ', - s : 'մի քանի վայրկյան', - m : 'րոպե', - mm : '%d րոպե', - h : 'ժամ', - hh : '%d ժամ', - d : 'օր', - dd : '%d օր', - M : 'ամիս', - MM : '%d ամիս', - y : 'տարի', - yy : '%d տարի' - }, - meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/, - isPM: function (input) { - return /^(ցերեկվա|երեկոյան)$/.test(input); - }, - meridiem : function (hour) { - if (hour < 4) { - return 'գիշերվա'; - } else if (hour < 12) { - return 'առավոտվա'; - } else if (hour < 17) { - return 'ցերեկվա'; - } else { - return 'երեկոյան'; - } - }, - ordinalParse: /\d{1,2}|\d{1,2}-(ին|րդ)/, - ordinal: function (number, period) { - switch (period) { - case 'DDD': - case 'w': - case 'W': - case 'DDDo': - if (number === 1) { - return number + '-ին'; - } - return number + '-րդ'; - default: - return number; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Bahasa Indonesia (id) - //! author : Mohammad Satrio Utomo : https://github.com/tyok - //! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan - - var id = _moment__default.defineLocale('id', { - months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'), - weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'), - weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'), - weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'), - longDateFormat : { - LT : 'HH.mm', - LTS : 'LT.ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY [pukul] LT', - LLLL : 'dddd, D MMMM YYYY [pukul] LT' - }, - meridiemParse: /pagi|siang|sore|malam/, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'pagi') { - return hour; - } else if (meridiem === 'siang') { - return hour >= 11 ? hour : hour + 12; - } else if (meridiem === 'sore' || meridiem === 'malam') { - return hour + 12; - } - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 11) { - return 'pagi'; - } else if (hours < 15) { - return 'siang'; - } else if (hours < 19) { - return 'sore'; - } else { - return 'malam'; - } - }, - calendar : { - sameDay : '[Hari ini pukul] LT', - nextDay : '[Besok pukul] LT', - nextWeek : 'dddd [pukul] LT', - lastDay : '[Kemarin pukul] LT', - lastWeek : 'dddd [lalu pukul] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'dalam %s', - past : '%s yang lalu', - s : 'beberapa detik', - m : 'semenit', - mm : '%d menit', - h : 'sejam', - hh : '%d jam', - d : 'sehari', - dd : '%d hari', - M : 'sebulan', - MM : '%d bulan', - y : 'setahun', - yy : '%d tahun' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : icelandic (is) - //! author : Hinrik Örn Sigurðsson : https://github.com/hinrik - - function is__plural(n) { - if (n % 100 === 11) { - return true; - } else if (n % 10 === 1) { - return false; - } - return true; - } - function is__translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': - return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum'; - case 'm': - return withoutSuffix ? 'mínúta' : 'mínútu'; - case 'mm': - if (is__plural(number)) { - return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum'); - } else if (withoutSuffix) { - return result + 'mínúta'; - } - return result + 'mínútu'; - case 'hh': - if (is__plural(number)) { - return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum'); - } - return result + 'klukkustund'; - case 'd': - if (withoutSuffix) { - return 'dagur'; - } - return isFuture ? 'dag' : 'degi'; - case 'dd': - if (is__plural(number)) { - if (withoutSuffix) { - return result + 'dagar'; - } - return result + (isFuture ? 'daga' : 'dögum'); - } else if (withoutSuffix) { - return result + 'dagur'; - } - return result + (isFuture ? 'dag' : 'degi'); - case 'M': - if (withoutSuffix) { - return 'mánuður'; - } - return isFuture ? 'mánuð' : 'mánuði'; - case 'MM': - if (is__plural(number)) { - if (withoutSuffix) { - return result + 'mánuðir'; - } - return result + (isFuture ? 'mánuði' : 'mánuðum'); - } else if (withoutSuffix) { - return result + 'mánuður'; - } - return result + (isFuture ? 'mánuð' : 'mánuði'); - case 'y': - return withoutSuffix || isFuture ? 'ár' : 'ári'; - case 'yy': - if (is__plural(number)) { - return result + (withoutSuffix || isFuture ? 'ár' : 'árum'); - } - return result + (withoutSuffix || isFuture ? 'ár' : 'ári'); - } - } - - var is = _moment__default.defineLocale('is', { - months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'), - weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'), - weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'), - weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY [kl.] LT', - LLLL : 'dddd, D. MMMM YYYY [kl.] LT' - }, - calendar : { - sameDay : '[í dag kl.] LT', - nextDay : '[á morgun kl.] LT', - nextWeek : 'dddd [kl.] LT', - lastDay : '[í gær kl.] LT', - lastWeek : '[síðasta] dddd [kl.] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'eftir %s', - past : 'fyrir %s síðan', - s : is__translate, - m : is__translate, - mm : is__translate, - h : 'klukkustund', - hh : is__translate, - d : is__translate, - dd : is__translate, - M : is__translate, - MM : is__translate, - y : is__translate, - yy : is__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : italian (it) - //! author : Lorenzo : https://github.com/aliem - //! author: Mattia Larentis: https://github.com/nostalgiaz - - var it = _moment__default.defineLocale('it', { - months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'), - monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), - weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'), - weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'), - weekdaysMin : 'D_L_Ma_Me_G_V_S'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Oggi alle] LT', - nextDay: '[Domani alle] LT', - nextWeek: 'dddd [alle] LT', - lastDay: '[Ieri alle] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[la scorsa] dddd [alle] LT'; - default: - return '[lo scorso] dddd [alle] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : function (s) { - return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s; - }, - past : '%s fa', - s : 'alcuni secondi', - m : 'un minuto', - mm : '%d minuti', - h : 'un\'ora', - hh : '%d ore', - d : 'un giorno', - dd : '%d giorni', - M : 'un mese', - MM : '%d mesi', - y : 'un anno', - yy : '%d anni' - }, - ordinalParse : /\d{1,2}º/, - ordinal: '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : japanese (ja) - //! author : LI Long : https://github.com/baryon - - var ja = _moment__default.defineLocale('ja', { - months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'), - weekdaysShort : '日_月_火_水_木_金_土'.split('_'), - weekdaysMin : '日_月_火_水_木_金_土'.split('_'), - longDateFormat : { - LT : 'Ah時m分', - LTS : 'LTs秒', - L : 'YYYY/MM/DD', - LL : 'YYYY年M月D日', - LLL : 'YYYY年M月D日LT', - LLLL : 'YYYY年M月D日LT dddd' - }, - meridiemParse: /午前|午後/i, - isPM : function (input) { - return input === '午後'; - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return '午前'; - } else { - return '午後'; - } - }, - calendar : { - sameDay : '[今日] LT', - nextDay : '[明日] LT', - nextWeek : '[来週]dddd LT', - lastDay : '[昨日] LT', - lastWeek : '[前週]dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s後', - past : '%s前', - s : '数秒', - m : '1分', - mm : '%d分', - h : '1時間', - hh : '%d時間', - d : '1日', - dd : '%d日', - M : '1ヶ月', - MM : '%dヶ月', - y : '1年', - yy : '%d年' - } - }); - - //! moment.js locale configuration - //! locale : Boso Jowo (jv) - //! author : Rony Lantip : https://github.com/lantip - //! reference: http://jv.wikipedia.org/wiki/Basa_Jawa - - var jv = _moment__default.defineLocale('jv', { - months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'), - weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'), - weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'), - weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'), - longDateFormat : { - LT : 'HH.mm', - LTS : 'LT.ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY [pukul] LT', - LLLL : 'dddd, D MMMM YYYY [pukul] LT' - }, - meridiemParse: /enjing|siyang|sonten|ndalu/, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'enjing') { - return hour; - } else if (meridiem === 'siyang') { - return hour >= 11 ? hour : hour + 12; - } else if (meridiem === 'sonten' || meridiem === 'ndalu') { - return hour + 12; - } - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 11) { - return 'enjing'; - } else if (hours < 15) { - return 'siyang'; - } else if (hours < 19) { - return 'sonten'; - } else { - return 'ndalu'; - } - }, - calendar : { - sameDay : '[Dinten puniko pukul] LT', - nextDay : '[Mbenjang pukul] LT', - nextWeek : 'dddd [pukul] LT', - lastDay : '[Kala wingi pukul] LT', - lastWeek : 'dddd [kepengker pukul] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'wonten ing %s', - past : '%s ingkang kepengker', - s : 'sawetawis detik', - m : 'setunggal menit', - mm : '%d menit', - h : 'setunggal jam', - hh : '%d jam', - d : 'sedinten', - dd : '%d dinten', - M : 'sewulan', - MM : '%d wulan', - y : 'setaun', - yy : '%d taun' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Georgian (ka) - //! author : Irakli Janiashvili : https://github.com/irakli-janiashvili - - function ka__monthsCaseReplace(m, format) { - var months = { - 'nominative': 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'), - 'accusative': 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_') - }, - nounCase = (/D[oD] *MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - return months[nounCase][m.month()]; - } - function ka__weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'), - 'accusative': 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_') - }, - nounCase = (/(წინა|შემდეგ)/).test(format) ? - 'accusative' : - 'nominative'; - return weekdays[nounCase][m.day()]; - } - - var ka = _moment__default.defineLocale('ka', { - months : ka__monthsCaseReplace, - monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'), - weekdays : ka__weekdaysCaseReplace, - weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'), - weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'), - longDateFormat : { - LT : 'h:mm A', - LTS : 'h:mm:ss A', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[დღეს] LT[-ზე]', - nextDay : '[ხვალ] LT[-ზე]', - lastDay : '[გუშინ] LT[-ზე]', - nextWeek : '[შემდეგ] dddd LT[-ზე]', - lastWeek : '[წინა] dddd LT-ზე', - sameElse : 'L' - }, - relativeTime : { - future : function (s) { - return (/(წამი|წუთი|საათი|წელი)/).test(s) ? - s.replace(/ი$/, 'ში') : - s + 'ში'; - }, - past : function (s) { - if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) { - return s.replace(/(ი|ე)$/, 'ის წინ'); - } - if ((/წელი/).test(s)) { - return s.replace(/წელი$/, 'წლის წინ'); - } - }, - s : 'რამდენიმე წამი', - m : 'წუთი', - mm : '%d წუთი', - h : 'საათი', - hh : '%d საათი', - d : 'დღე', - dd : '%d დღე', - M : 'თვე', - MM : '%d თვე', - y : 'წელი', - yy : '%d წელი' - }, - ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/, - ordinal : function (number) { - if (number === 0) { - return number; - } - if (number === 1) { - return number + '-ლი'; - } - if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) { - return 'მე-' + number; - } - return number + '-ე'; - }, - week : { - dow : 1, - doy : 7 - } - }); - - //! moment.js locale configuration - //! locale : khmer (km) - //! author : Kruy Vanna : https://github.com/kruyvanna - - var km = _moment__default.defineLocale('km', { - months: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'), - monthsShort: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'), - weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), - weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), - weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), - longDateFormat: { - LT: 'HH:mm', - LTS : 'LT:ss', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd, D MMMM YYYY LT' - }, - calendar: { - sameDay: '[ថ្ងៃនៈ ម៉ោង] LT', - nextDay: '[ស្អែក ម៉ោង] LT', - nextWeek: 'dddd [ម៉ោង] LT', - lastDay: '[ម្សិលមិញ ម៉ោង] LT', - lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT', - sameElse: 'L' - }, - relativeTime: { - future: '%sទៀត', - past: '%sមុន', - s: 'ប៉ុន្មានវិនាទី', - m: 'មួយនាទី', - mm: '%d នាទី', - h: 'មួយម៉ោង', - hh: '%d ម៉ោង', - d: 'មួយថ្ងៃ', - dd: '%d ថ្ងៃ', - M: 'មួយខែ', - MM: '%d ខែ', - y: 'មួយឆ្នាំ', - yy: '%d ឆ្នាំ' - }, - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : korean (ko) - //! - //! authors - //! - //! - Kyungwook, Park : https://github.com/kyungw00k - //! - Jeeeyul Lee - - var ko = _moment__default.defineLocale('ko', { - months : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), - monthsShort : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), - weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'), - weekdaysShort : '일_월_화_수_목_금_토'.split('_'), - weekdaysMin : '일_월_화_수_목_금_토'.split('_'), - longDateFormat : { - LT : 'A h시 m분', - LTS : 'A h시 m분 s초', - L : 'YYYY.MM.DD', - LL : 'YYYY년 MMMM D일', - LLL : 'YYYY년 MMMM D일 LT', - LLLL : 'YYYY년 MMMM D일 dddd LT' - }, - calendar : { - sameDay : '오늘 LT', - nextDay : '내일 LT', - nextWeek : 'dddd LT', - lastDay : '어제 LT', - lastWeek : '지난주 dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s 후', - past : '%s 전', - s : '몇초', - ss : '%d초', - m : '일분', - mm : '%d분', - h : '한시간', - hh : '%d시간', - d : '하루', - dd : '%d일', - M : '한달', - MM : '%d달', - y : '일년', - yy : '%d년' - }, - ordinalParse : /\d{1,2}일/, - ordinal : '%d일', - meridiemParse : /오전|오후/, - isPM : function (token) { - return token === '오후'; - }, - meridiem : function (hour, minute, isUpper) { - return hour < 12 ? '오전' : '오후'; - } - }); - - //! moment.js locale configuration - //! locale : Luxembourgish (lb) - //! author : mweimerskirch : https://github.com/mweimerskirch, David Raison : https://github.com/kwisatz - - function lb__processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 'm': ['eng Minutt', 'enger Minutt'], - 'h': ['eng Stonn', 'enger Stonn'], - 'd': ['een Dag', 'engem Dag'], - 'M': ['ee Mount', 'engem Mount'], - 'y': ['ee Joer', 'engem Joer'] - }; - return withoutSuffix ? format[key][0] : format[key][1]; - } - function processFutureTime(string) { - var number = string.substr(0, string.indexOf(' ')); - if (eifelerRegelAppliesToNumber(number)) { - return 'a ' + string; - } - return 'an ' + string; - } - function processPastTime(string) { - var number = string.substr(0, string.indexOf(' ')); - if (eifelerRegelAppliesToNumber(number)) { - return 'viru ' + string; - } - return 'virun ' + string; - } - /** - * Returns true if the word before the given number loses the '-n' ending. - * e.g. 'an 10 Deeg' but 'a 5 Deeg' - * - * @param number {integer} - * @returns {boolean} - */ - function eifelerRegelAppliesToNumber(number) { - number = parseInt(number, 10); - if (isNaN(number)) { - return false; - } - if (number < 0) { - // Negative Number --> always true - return true; - } else if (number < 10) { - // Only 1 digit - if (4 <= number && number <= 7) { - return true; - } - return false; - } else if (number < 100) { - // 2 digits - var lastDigit = number % 10, firstDigit = number / 10; - if (lastDigit === 0) { - return eifelerRegelAppliesToNumber(firstDigit); - } - return eifelerRegelAppliesToNumber(lastDigit); - } else if (number < 10000) { - // 3 or 4 digits --> recursively check first digit - while (number >= 10) { - number = number / 10; - } - return eifelerRegelAppliesToNumber(number); - } else { - // Anything larger than 4 digits: recursively check first n-3 digits - number = number / 1000; - return eifelerRegelAppliesToNumber(number); - } - } - - var lb = _moment__default.defineLocale('lb', { - months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), - monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'), - weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'), - weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'), - weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'), - longDateFormat: { - LT: 'H:mm [Auer]', - LTS: 'H:mm:ss [Auer]', - L: 'DD.MM.YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[Haut um] LT', - sameElse: 'L', - nextDay: '[Muer um] LT', - nextWeek: 'dddd [um] LT', - lastDay: '[Gëschter um] LT', - lastWeek: function () { - // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule - switch (this.day()) { - case 2: - case 4: - return '[Leschten] dddd [um] LT'; - default: - return '[Leschte] dddd [um] LT'; - } - } - }, - relativeTime : { - future : processFutureTime, - past : processPastTime, - s : 'e puer Sekonnen', - m : lb__processRelativeTime, - mm : '%d Minutten', - h : lb__processRelativeTime, - hh : '%d Stonnen', - d : lb__processRelativeTime, - dd : '%d Deeg', - M : lb__processRelativeTime, - MM : '%d Méint', - y : lb__processRelativeTime, - yy : '%d Joer' - }, - ordinalParse: /\d{1,2}\./, - ordinal: '%d.', - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Lithuanian (lt) - //! author : Mindaugas Mozūras : https://github.com/mmozuras - - var lt__units = { - 'm' : 'minutė_minutės_minutę', - 'mm': 'minutės_minučių_minutes', - 'h' : 'valanda_valandos_valandą', - 'hh': 'valandos_valandų_valandas', - 'd' : 'diena_dienos_dieną', - 'dd': 'dienos_dienų_dienas', - 'M' : 'mėnuo_mėnesio_mėnesį', - 'MM': 'mėnesiai_mėnesių_mėnesius', - 'y' : 'metai_metų_metus', - 'yy': 'metai_metų_metus' - }, - weekDays = 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'); - function translateSeconds(number, withoutSuffix, key, isFuture) { - if (withoutSuffix) { - return 'kelios sekundės'; - } else { - return isFuture ? 'kelių sekundžių' : 'kelias sekundes'; - } - } - function translateSingular(number, withoutSuffix, key, isFuture) { - return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]); - } - function special(number) { - return number % 10 === 0 || (number > 10 && number < 20); - } - function forms(key) { - return lt__units[key].split('_'); - } - function lt__translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - if (number === 1) { - return result + translateSingular(number, withoutSuffix, key[0], isFuture); - } else if (withoutSuffix) { - return result + (special(number) ? forms(key)[1] : forms(key)[0]); - } else { - if (isFuture) { - return result + forms(key)[1]; - } else { - return result + (special(number) ? forms(key)[1] : forms(key)[2]); - } - } - } - function relativeWeekDay(moment, format) { - var nominative = format.indexOf('dddd HH:mm') === -1, - weekDay = weekDays[moment.day()]; - return nominative ? weekDay : weekDay.substring(0, weekDay.length - 2) + 'į'; - } - - var lt = _moment__default.defineLocale('lt', { - months : 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'), - monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'), - weekdays : relativeWeekDay, - weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'), - weekdaysMin : 'S_P_A_T_K_Pn_Š'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'YYYY-MM-DD', - LL : 'YYYY [m.] MMMM D [d.]', - LLL : 'YYYY [m.] MMMM D [d.], LT [val.]', - LLLL : 'YYYY [m.] MMMM D [d.], dddd, LT [val.]', - l : 'YYYY-MM-DD', - ll : 'YYYY [m.] MMMM D [d.]', - lll : 'YYYY [m.] MMMM D [d.], LT [val.]', - llll : 'YYYY [m.] MMMM D [d.], ddd, LT [val.]' - }, - calendar : { - sameDay : '[Šiandien] LT', - nextDay : '[Rytoj] LT', - nextWeek : 'dddd LT', - lastDay : '[Vakar] LT', - lastWeek : '[Praėjusį] dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : 'po %s', - past : 'prieš %s', - s : translateSeconds, - m : translateSingular, - mm : lt__translate, - h : translateSingular, - hh : lt__translate, - d : translateSingular, - dd : lt__translate, - M : translateSingular, - MM : lt__translate, - y : translateSingular, - yy : lt__translate - }, - ordinalParse: /\d{1,2}-oji/, - ordinal : function (number) { - return number + '-oji'; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : latvian (lv) - //! author : Kristaps Karlsons : https://github.com/skakri - //! author : Jānis Elmeris : https://github.com/JanisE - - var lv__units = { - 'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'), - 'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'), - 'h': 'stundas_stundām_stunda_stundas'.split('_'), - 'hh': 'stundas_stundām_stunda_stundas'.split('_'), - 'd': 'dienas_dienām_diena_dienas'.split('_'), - 'dd': 'dienas_dienām_diena_dienas'.split('_'), - 'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'), - 'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'), - 'y': 'gada_gadiem_gads_gadi'.split('_'), - 'yy': 'gada_gadiem_gads_gadi'.split('_') - }; - /** - * @param withoutSuffix boolean true = a length of time; false = before/after a period of time. - */ - function lv__format(forms, number, withoutSuffix) { - if (withoutSuffix) { - // E.g. "21 minūte", "3 minūtes". - return number % 10 === 1 && number !== 11 ? forms[2] : forms[3]; - } else { - // E.g. "21 minūtes" as in "pēc 21 minūtes". - // E.g. "3 minūtēm" as in "pēc 3 minūtēm". - return number % 10 === 1 && number !== 11 ? forms[0] : forms[1]; - } - } - function lv__relativeTimeWithPlural(number, withoutSuffix, key) { - return number + ' ' + lv__format(lv__units[key], number, withoutSuffix); - } - function relativeTimeWithSingular(number, withoutSuffix, key) { - return lv__format(lv__units[key], number, withoutSuffix); - } - function relativeSeconds(number, withoutSuffix) { - return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm'; - } - - var lv = _moment__default.defineLocale('lv', { - months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'), - weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'), - weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'), - weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY.', - LL : 'YYYY. [gada] D. MMMM', - LLL : 'YYYY. [gada] D. MMMM, LT', - LLLL : 'YYYY. [gada] D. MMMM, dddd, LT' - }, - calendar : { - sameDay : '[Šodien pulksten] LT', - nextDay : '[Rīt pulksten] LT', - nextWeek : 'dddd [pulksten] LT', - lastDay : '[Vakar pulksten] LT', - lastWeek : '[Pagājušā] dddd [pulksten] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'pēc %s', - past : 'pirms %s', - s : relativeSeconds, - m : relativeTimeWithSingular, - mm : lv__relativeTimeWithPlural, - h : relativeTimeWithSingular, - hh : lv__relativeTimeWithPlural, - d : relativeTimeWithSingular, - dd : lv__relativeTimeWithPlural, - M : relativeTimeWithSingular, - MM : lv__relativeTimeWithPlural, - y : relativeTimeWithSingular, - yy : lv__relativeTimeWithPlural - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Montenegrin (me) - //! author : Miodrag Nikač : https://github.com/miodragnikac - - var me__translator = { - words: { //Different grammatical cases - m: ['jedan minut', 'jednog minuta'], - mm: ['minut', 'minuta', 'minuta'], - h: ['jedan sat', 'jednog sata'], - hh: ['sat', 'sata', 'sati'], - dd: ['dan', 'dana', 'dana'], - MM: ['mjesec', 'mjeseca', 'mjeseci'], - yy: ['godina', 'godine', 'godina'] - }, - correctGrammaticalCase: function (number, wordKey) { - return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]); - }, - translate: function (number, withoutSuffix, key) { - var wordKey = me__translator.words[key]; - if (key.length === 1) { - return withoutSuffix ? wordKey[0] : wordKey[1]; - } else { - return number + ' ' + me__translator.correctGrammaticalCase(number, wordKey); - } - } - }; - - var me = _moment__default.defineLocale('me', { - months: ['januar', 'februar', 'mart', 'april', 'maj', 'jun', 'jul', 'avgust', 'septembar', 'oktobar', 'novembar', 'decembar'], - monthsShort: ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun', 'jul', 'avg.', 'sep.', 'okt.', 'nov.', 'dec.'], - weekdays: ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'], - weekdaysShort: ['ned.', 'pon.', 'uto.', 'sri.', 'čet.', 'pet.', 'sub.'], - weekdaysMin: ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'], - longDateFormat: { - LT: 'H:mm', - LTS : 'LT:ss', - L: 'DD. MM. YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[danas u] LT', - nextDay: '[sjutra u] LT', - - nextWeek: function () { - switch (this.day()) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[juče u] LT', - lastWeek : function () { - var lastWeekDays = [ - '[prošle] [nedjelje] [u] LT', - '[prošlog] [ponedjeljka] [u] LT', - '[prošlog] [utorka] [u] LT', - '[prošle] [srijede] [u] LT', - '[prošlog] [četvrtka] [u] LT', - '[prošlog] [petka] [u] LT', - '[prošle] [subote] [u] LT' - ]; - return lastWeekDays[this.day()]; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'prije %s', - s : 'nekoliko sekundi', - m : me__translator.translate, - mm : me__translator.translate, - h : me__translator.translate, - hh : me__translator.translate, - d : 'dan', - dd : me__translator.translate, - M : 'mjesec', - MM : me__translator.translate, - y : 'godinu', - yy : me__translator.translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : macedonian (mk) - //! author : Borislav Mickov : https://github.com/B0k0 - - var mk = _moment__default.defineLocale('mk', { - months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'), - monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'), - weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'), - weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'), - weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'D.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Денес во] LT', - nextDay : '[Утре во] LT', - nextWeek : 'dddd [во] LT', - lastDay : '[Вчера во] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - case 6: - return '[Во изминатата] dddd [во] LT'; - case 1: - case 2: - case 4: - case 5: - return '[Во изминатиот] dddd [во] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'после %s', - past : 'пред %s', - s : 'неколку секунди', - m : 'минута', - mm : '%d минути', - h : 'час', - hh : '%d часа', - d : 'ден', - dd : '%d дена', - M : 'месец', - MM : '%d месеци', - y : 'година', - yy : '%d години' - }, - ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, - ordinal : function (number) { - var lastDigit = number % 10, - last2Digits = number % 100; - if (number === 0) { - return number + '-ев'; - } else if (last2Digits === 0) { - return number + '-ен'; - } else if (last2Digits > 10 && last2Digits < 20) { - return number + '-ти'; - } else if (lastDigit === 1) { - return number + '-ви'; - } else if (lastDigit === 2) { - return number + '-ри'; - } else if (lastDigit === 7 || lastDigit === 8) { - return number + '-ми'; - } else { - return number + '-ти'; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : malayalam (ml) - //! author : Floyd Pink : https://github.com/floydpink - - var ml = _moment__default.defineLocale('ml', { - months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'), - monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'), - weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'), - weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'), - weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'), - longDateFormat : { - LT : 'A h:mm -നു', - LTS : 'A h:mm:ss -നു', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[ഇന്ന്] LT', - nextDay : '[നാളെ] LT', - nextWeek : 'dddd, LT', - lastDay : '[ഇന്നലെ] LT', - lastWeek : '[കഴിഞ്ഞ] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s കഴിഞ്ഞ്', - past : '%s മുൻപ്', - s : 'അൽപ നിമിഷങ്ങൾ', - m : 'ഒരു മിനിറ്റ്', - mm : '%d മിനിറ്റ്', - h : 'ഒരു മണിക്കൂർ', - hh : '%d മണിക്കൂർ', - d : 'ഒരു ദിവസം', - dd : '%d ദിവസം', - M : 'ഒരു മാസം', - MM : '%d മാസം', - y : 'ഒരു വർഷം', - yy : '%d വർഷം' - }, - meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i, - isPM : function (input) { - return /^(ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി)$/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'രാത്രി'; - } else if (hour < 12) { - return 'രാവിലെ'; - } else if (hour < 17) { - return 'ഉച്ച കഴിഞ്ഞ്'; - } else if (hour < 20) { - return 'വൈകുന്നേരം'; - } else { - return 'രാത്രി'; - } - } - }); - - //! moment.js locale configuration - //! locale : Marathi (mr) - //! author : Harshad Kale : https://github.com/kalehv - - var mr__symbolMap = { - '1': '१', - '2': '२', - '3': '३', - '4': '४', - '5': '५', - '6': '६', - '7': '७', - '8': '८', - '9': '९', - '0': '०' - }, - mr__numberMap = { - '१': '1', - '२': '2', - '३': '3', - '४': '4', - '५': '5', - '६': '6', - '७': '7', - '८': '8', - '९': '9', - '०': '0' - }; - - var mr = _moment__default.defineLocale('mr', { - months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'), - monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'), - weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'), - weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'), - weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'), - longDateFormat : { - LT : 'A h:mm वाजता', - LTS : 'A h:mm:ss वाजता', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[आज] LT', - nextDay : '[उद्या] LT', - nextWeek : 'dddd, LT', - lastDay : '[काल] LT', - lastWeek: '[मागील] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s नंतर', - past : '%s पूर्वी', - s : 'सेकंद', - m: 'एक मिनिट', - mm: '%d मिनिटे', - h : 'एक तास', - hh : '%d तास', - d : 'एक दिवस', - dd : '%d दिवस', - M : 'एक महिना', - MM : '%d महिने', - y : 'एक वर्ष', - yy : '%d वर्षे' - }, - preparse: function (string) { - return string.replace(/[१२३४५६७८९०]/g, function (match) { - return mr__numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return mr__symbolMap[match]; - }); - }, - meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'रात्री') { - return hour < 4 ? hour : hour + 12; - } else if (meridiem === 'सकाळी') { - return hour; - } else if (meridiem === 'दुपारी') { - return hour >= 10 ? hour : hour + 12; - } else if (meridiem === 'सायंकाळी') { - return hour + 12; - } - }, - meridiem: function (hour, minute, isLower) { - if (hour < 4) { - return 'रात्री'; - } else if (hour < 10) { - return 'सकाळी'; - } else if (hour < 17) { - return 'दुपारी'; - } else if (hour < 20) { - return 'सायंकाळी'; - } else { - return 'रात्री'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Bahasa Malaysia (ms-MY) - //! author : Weldan Jamili : https://github.com/weldan - - var ms_my = _moment__default.defineLocale('ms-my', { - months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'), - monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'), - weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'), - weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'), - weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'), - longDateFormat : { - LT : 'HH.mm', - LTS : 'LT.ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY [pukul] LT', - LLLL : 'dddd, D MMMM YYYY [pukul] LT' - }, - meridiemParse: /pagi|tengahari|petang|malam/, - meridiemHour: function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'pagi') { - return hour; - } else if (meridiem === 'tengahari') { - return hour >= 11 ? hour : hour + 12; - } else if (meridiem === 'petang' || meridiem === 'malam') { - return hour + 12; - } - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 11) { - return 'pagi'; - } else if (hours < 15) { - return 'tengahari'; - } else if (hours < 19) { - return 'petang'; - } else { - return 'malam'; - } - }, - calendar : { - sameDay : '[Hari ini pukul] LT', - nextDay : '[Esok pukul] LT', - nextWeek : 'dddd [pukul] LT', - lastDay : '[Kelmarin pukul] LT', - lastWeek : 'dddd [lepas pukul] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'dalam %s', - past : '%s yang lepas', - s : 'beberapa saat', - m : 'seminit', - mm : '%d minit', - h : 'sejam', - hh : '%d jam', - d : 'sehari', - dd : '%d hari', - M : 'sebulan', - MM : '%d bulan', - y : 'setahun', - yy : '%d tahun' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Burmese (my) - //! author : Squar team, mysquar.com - - var my__symbolMap = { - '1': '၁', - '2': '၂', - '3': '၃', - '4': '၄', - '5': '၅', - '6': '၆', - '7': '၇', - '8': '၈', - '9': '၉', - '0': '၀' - }, my__numberMap = { - '၁': '1', - '၂': '2', - '၃': '3', - '၄': '4', - '၅': '5', - '၆': '6', - '၇': '7', - '၈': '8', - '၉': '9', - '၀': '0' - }; - - var my = _moment__default.defineLocale('my', { - months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'), - monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'), - weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'), - weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'), - weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'), - - longDateFormat: { - LT: 'HH:mm', - LTS: 'HH:mm:ss', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd D MMMM YYYY LT' - }, - calendar: { - sameDay: '[ယနေ.] LT [မှာ]', - nextDay: '[မနက်ဖြန်] LT [မှာ]', - nextWeek: 'dddd LT [မှာ]', - lastDay: '[မနေ.က] LT [မှာ]', - lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]', - sameElse: 'L' - }, - relativeTime: { - future: 'လာမည့် %s မှာ', - past: 'လွန်ခဲ့သော %s က', - s: 'စက္ကန်.အနည်းငယ်', - m: 'တစ်မိနစ်', - mm: '%d မိနစ်', - h: 'တစ်နာရီ', - hh: '%d နာရီ', - d: 'တစ်ရက်', - dd: '%d ရက်', - M: 'တစ်လ', - MM: '%d လ', - y: 'တစ်နှစ်', - yy: '%d နှစ်' - }, - preparse: function (string) { - return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) { - return my__numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return my__symbolMap[match]; - }); - }, - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : norwegian bokmål (nb) - //! authors : Espen Hovlandsdal : https://github.com/rexxars - //! Sigurd Gartmann : https://github.com/sigurdga - - var nb = _moment__default.defineLocale('nb', { - months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), - weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), - weekdaysShort : 'søn_man_tirs_ons_tors_fre_lør'.split('_'), - weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'), - longDateFormat : { - LT : 'H.mm', - LTS : 'LT.ss', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY [kl.] LT', - LLLL : 'dddd D. MMMM YYYY [kl.] LT' - }, - calendar : { - sameDay: '[i dag kl.] LT', - nextDay: '[i morgen kl.] LT', - nextWeek: 'dddd [kl.] LT', - lastDay: '[i går kl.] LT', - lastWeek: '[forrige] dddd [kl.] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'om %s', - past : 'for %s siden', - s : 'noen sekunder', - m : 'ett minutt', - mm : '%d minutter', - h : 'en time', - hh : '%d timer', - d : 'en dag', - dd : '%d dager', - M : 'en måned', - MM : '%d måneder', - y : 'ett år', - yy : '%d år' - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : nepali/nepalese - //! author : suvash : https://github.com/suvash - - var ne__symbolMap = { - '1': '१', - '2': '२', - '3': '३', - '4': '४', - '5': '५', - '6': '६', - '7': '७', - '8': '८', - '9': '९', - '0': '०' - }, - ne__numberMap = { - '१': '1', - '२': '2', - '३': '3', - '४': '4', - '५': '5', - '६': '6', - '७': '7', - '८': '8', - '९': '9', - '०': '0' - }; - - var ne = _moment__default.defineLocale('ne', { - months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'), - monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'), - weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'), - weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'), - weekdaysMin : 'आइ._सो._मङ्_बु._बि._शु._श.'.split('_'), - longDateFormat : { - LT : 'Aको h:mm बजे', - LTS : 'Aको h:mm:ss बजे', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - preparse: function (string) { - return string.replace(/[१२३४५६७८९०]/g, function (match) { - return ne__numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return ne__symbolMap[match]; - }); - }, - meridiemParse: /राती|बिहान|दिउँसो|बेलुका|साँझ|राती/, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'राती') { - return hour < 3 ? hour : hour + 12; - } else if (meridiem === 'बिहान') { - return hour; - } else if (meridiem === 'दिउँसो') { - return hour >= 10 ? hour : hour + 12; - } else if (meridiem === 'बेलुका' || meridiem === 'साँझ') { - return hour + 12; - } - }, - meridiem : function (hour, minute, isLower) { - if (hour < 3) { - return 'राती'; - } else if (hour < 10) { - return 'बिहान'; - } else if (hour < 15) { - return 'दिउँसो'; - } else if (hour < 18) { - return 'बेलुका'; - } else if (hour < 20) { - return 'साँझ'; - } else { - return 'राती'; - } - }, - calendar : { - sameDay : '[आज] LT', - nextDay : '[भोली] LT', - nextWeek : '[आउँदो] dddd[,] LT', - lastDay : '[हिजो] LT', - lastWeek : '[गएको] dddd[,] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%sमा', - past : '%s अगाडी', - s : 'केही समय', - m : 'एक मिनेट', - mm : '%d मिनेट', - h : 'एक घण्टा', - hh : '%d घण्टा', - d : 'एक दिन', - dd : '%d दिन', - M : 'एक महिना', - MM : '%d महिना', - y : 'एक बर्ष', - yy : '%d बर्ष' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : dutch (nl) - //! author : Joris Röling : https://github.com/jjupiter - - var nl__monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'), - nl__monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'); - - var nl = _moment__default.defineLocale('nl', { - months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'), - monthsShort : function (m, format) { - if (/-MMM-/.test(format)) { - return nl__monthsShortWithoutDots[m.month()]; - } else { - return nl__monthsShortWithDots[m.month()]; - } - }, - weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'), - weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'), - weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD-MM-YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[vandaag om] LT', - nextDay: '[morgen om] LT', - nextWeek: 'dddd [om] LT', - lastDay: '[gisteren om] LT', - lastWeek: '[afgelopen] dddd [om] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'over %s', - past : '%s geleden', - s : 'een paar seconden', - m : 'één minuut', - mm : '%d minuten', - h : 'één uur', - hh : '%d uur', - d : 'één dag', - dd : '%d dagen', - M : 'één maand', - MM : '%d maanden', - y : 'één jaar', - yy : '%d jaar' - }, - ordinalParse: /\d{1,2}(ste|de)/, - ordinal : function (number) { - return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : norwegian nynorsk (nn) - //! author : https://github.com/mechuwind - - var nn = _moment__default.defineLocale('nn', { - months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), - weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'), - weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'), - weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[I dag klokka] LT', - nextDay: '[I morgon klokka] LT', - nextWeek: 'dddd [klokka] LT', - lastDay: '[I går klokka] LT', - lastWeek: '[Føregåande] dddd [klokka] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'om %s', - past : 'for %s sidan', - s : 'nokre sekund', - m : 'eit minutt', - mm : '%d minutt', - h : 'ein time', - hh : '%d timar', - d : 'ein dag', - dd : '%d dagar', - M : 'ein månad', - MM : '%d månader', - y : 'eit år', - yy : '%d år' - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : polish (pl) - //! author : Rafal Hirsz : https://github.com/evoL - - var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_'), - monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_'); - function pl__plural(n) { - return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1); - } - function pl__translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'minuta' : 'minutę'; - case 'mm': - return result + (pl__plural(number) ? 'minuty' : 'minut'); - case 'h': - return withoutSuffix ? 'godzina' : 'godzinę'; - case 'hh': - return result + (pl__plural(number) ? 'godziny' : 'godzin'); - case 'MM': - return result + (pl__plural(number) ? 'miesiące' : 'miesięcy'); - case 'yy': - return result + (pl__plural(number) ? 'lata' : 'lat'); - } - } - - var pl = _moment__default.defineLocale('pl', { - months : function (momentToFormat, format) { - if (format === '') { - // Hack: if format empty we know this is used to generate - // RegExp by moment. Give then back both valid forms of months - // in RegExp ready format. - return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')'; - } else if (/D MMMM/.test(format)) { - return monthsSubjective[momentToFormat.month()]; - } else { - return monthsNominative[momentToFormat.month()]; - } - }, - monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'), - weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'), - weekdaysShort : 'nie_pon_wt_śr_czw_pt_sb'.split('_'), - weekdaysMin : 'N_Pn_Wt_Śr_Cz_Pt_So'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Dziś o] LT', - nextDay: '[Jutro o] LT', - nextWeek: '[W] dddd [o] LT', - lastDay: '[Wczoraj o] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[W zeszłą niedzielę o] LT'; - case 3: - return '[W zeszłą środę o] LT'; - case 6: - return '[W zeszłą sobotę o] LT'; - default: - return '[W zeszły] dddd [o] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'za %s', - past : '%s temu', - s : 'kilka sekund', - m : pl__translate, - mm : pl__translate, - h : pl__translate, - hh : pl__translate, - d : '1 dzień', - dd : '%d dni', - M : 'miesiąc', - MM : pl__translate, - y : 'rok', - yy : pl__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : brazilian portuguese (pt-br) - //! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira - - var pt_br = _moment__default.defineLocale('pt-br', { - months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'), - monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'), - weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'), - weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'), - weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D [de] MMMM [de] YYYY', - LLL : 'D [de] MMMM [de] YYYY [às] LT', - LLLL : 'dddd, D [de] MMMM [de] YYYY [às] LT' - }, - calendar : { - sameDay: '[Hoje às] LT', - nextDay: '[Amanhã às] LT', - nextWeek: 'dddd [às] LT', - lastDay: '[Ontem às] LT', - lastWeek: function () { - return (this.day() === 0 || this.day() === 6) ? - '[Último] dddd [às] LT' : // Saturday + Sunday - '[Última] dddd [às] LT'; // Monday - Friday - }, - sameElse: 'L' - }, - relativeTime : { - future : 'em %s', - past : '%s atrás', - s : 'segundos', - m : 'um minuto', - mm : '%d minutos', - h : 'uma hora', - hh : '%d horas', - d : 'um dia', - dd : '%d dias', - M : 'um mês', - MM : '%d meses', - y : 'um ano', - yy : '%d anos' - }, - ordinalParse: /\d{1,2}º/, - ordinal : '%dº' - }); - - //! moment.js locale configuration - //! locale : portuguese (pt) - //! author : Jefferson : https://github.com/jalex79 - - var pt = _moment__default.defineLocale('pt', { - months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'), - monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'), - weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'), - weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'), - weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D [de] MMMM [de] YYYY', - LLL : 'D [de] MMMM [de] YYYY LT', - LLLL : 'dddd, D [de] MMMM [de] YYYY LT' - }, - calendar : { - sameDay: '[Hoje às] LT', - nextDay: '[Amanhã às] LT', - nextWeek: 'dddd [às] LT', - lastDay: '[Ontem às] LT', - lastWeek: function () { - return (this.day() === 0 || this.day() === 6) ? - '[Último] dddd [às] LT' : // Saturday + Sunday - '[Última] dddd [às] LT'; // Monday - Friday - }, - sameElse: 'L' - }, - relativeTime : { - future : 'em %s', - past : 'há %s', - s : 'segundos', - m : 'um minuto', - mm : '%d minutos', - h : 'uma hora', - hh : '%d horas', - d : 'um dia', - dd : '%d dias', - M : 'um mês', - MM : '%d meses', - y : 'um ano', - yy : '%d anos' - }, - ordinalParse: /\d{1,2}º/, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : romanian (ro) - //! author : Vlad Gurdiga : https://github.com/gurdiga - //! author : Valentin Agachi : https://github.com/avaly - - function ro__relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': 'minute', - 'hh': 'ore', - 'dd': 'zile', - 'MM': 'luni', - 'yy': 'ani' - }, - separator = ' '; - if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) { - separator = ' de '; - } - return number + separator + format[key]; - } - - var ro = _moment__default.defineLocale('ro', { - months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'), - monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'), - weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'), - weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'), - weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY H:mm', - LLLL : 'dddd, D MMMM YYYY H:mm' - }, - calendar : { - sameDay: '[azi la] LT', - nextDay: '[mâine la] LT', - nextWeek: 'dddd [la] LT', - lastDay: '[ieri la] LT', - lastWeek: '[fosta] dddd [la] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'peste %s', - past : '%s în urmă', - s : 'câteva secunde', - m : 'un minut', - mm : ro__relativeTimeWithPlural, - h : 'o oră', - hh : ro__relativeTimeWithPlural, - d : 'o zi', - dd : ro__relativeTimeWithPlural, - M : 'o lună', - MM : ro__relativeTimeWithPlural, - y : 'un an', - yy : ro__relativeTimeWithPlural - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : russian (ru) - //! author : Viktorminator : https://github.com/Viktorminator - //! Author : Menelion Elensúle : https://github.com/Oire - - function ru__plural(word, num) { - var forms = word.split('_'); - return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); - } - function ru__relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут', - 'hh': 'час_часа_часов', - 'dd': 'день_дня_дней', - 'MM': 'месяц_месяца_месяцев', - 'yy': 'год_года_лет' - }; - if (key === 'm') { - return withoutSuffix ? 'минута' : 'минуту'; - } - else { - return number + ' ' + ru__plural(format[key], +number); - } - } - function ru__monthsCaseReplace(m, format) { - var months = { - 'nominative': 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'), - 'accusative': 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_') - }, - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - return months[nounCase][m.month()]; - } - function ru__monthsShortCaseReplace(m, format) { - var monthsShort = { - 'nominative': 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'), - 'accusative': 'янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек'.split('_') - }, - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - return monthsShort[nounCase][m.month()]; - } - function ru__weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'), - 'accusative': 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_') - }, - nounCase = (/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/).test(format) ? - 'accusative' : - 'nominative'; - return weekdays[nounCase][m.day()]; - } - - var ru = _moment__default.defineLocale('ru', { - months : ru__monthsCaseReplace, - monthsShort : ru__monthsShortCaseReplace, - weekdays : ru__weekdaysCaseReplace, - weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'), - weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'), - monthsParse : [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i], - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY г.', - LLL : 'D MMMM YYYY г., LT', - LLLL : 'dddd, D MMMM YYYY г., LT' - }, - calendar : { - sameDay: '[Сегодня в] LT', - nextDay: '[Завтра в] LT', - lastDay: '[Вчера в] LT', - nextWeek: function () { - return this.day() === 2 ? '[Во] dddd [в] LT' : '[В] dddd [в] LT'; - }, - lastWeek: function (now) { - if (now.week() !== this.week()) { - switch (this.day()) { - case 0: - return '[В прошлое] dddd [в] LT'; - case 1: - case 2: - case 4: - return '[В прошлый] dddd [в] LT'; - case 3: - case 5: - case 6: - return '[В прошлую] dddd [в] LT'; - } - } else { - if (this.day() === 2) { - return '[Во] dddd [в] LT'; - } else { - return '[В] dddd [в] LT'; - } - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'через %s', - past : '%s назад', - s : 'несколько секунд', - m : ru__relativeTimeWithPlural, - mm : ru__relativeTimeWithPlural, - h : 'час', - hh : ru__relativeTimeWithPlural, - d : 'день', - dd : ru__relativeTimeWithPlural, - M : 'месяц', - MM : ru__relativeTimeWithPlural, - y : 'год', - yy : ru__relativeTimeWithPlural - }, - meridiemParse: /ночи|утра|дня|вечера/i, - isPM : function (input) { - return /^(дня|вечера)$/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'ночи'; - } else if (hour < 12) { - return 'утра'; - } else if (hour < 17) { - return 'дня'; - } else { - return 'вечера'; - } - }, - ordinalParse: /\d{1,2}-(й|го|я)/, - ordinal: function (number, period) { - switch (period) { - case 'M': - case 'd': - case 'DDD': - return number + '-й'; - case 'D': - return number + '-го'; - case 'w': - case 'W': - return number + '-я'; - default: - return number; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Sinhalese (si) - //! author : Sampath Sitinamaluwa : https://github.com/sampathsris - - var si = _moment__default.defineLocale('si', { - months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'), - monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'), - weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'), - weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'), - weekdaysMin : 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'), - longDateFormat : { - LT : 'a h:mm', - LTS : 'a h:mm:ss', - L : 'YYYY/MM/DD', - LL : 'YYYY MMMM D', - LLL : 'YYYY MMMM D, LT', - LLLL : 'YYYY MMMM D [වැනි] dddd, LTS' - }, - calendar : { - sameDay : '[අද] LT[ට]', - nextDay : '[හෙට] LT[ට]', - nextWeek : 'dddd LT[ට]', - lastDay : '[ඊයේ] LT[ට]', - lastWeek : '[පසුගිය] dddd LT[ට]', - sameElse : 'L' - }, - relativeTime : { - future : '%sකින්', - past : '%sකට පෙර', - s : 'තත්පර කිහිපය', - m : 'මිනිත්තුව', - mm : 'මිනිත්තු %d', - h : 'පැය', - hh : 'පැය %d', - d : 'දිනය', - dd : 'දින %d', - M : 'මාසය', - MM : 'මාස %d', - y : 'වසර', - yy : 'වසර %d' - }, - ordinalParse: /\d{1,2} වැනි/, - ordinal : function (number) { - return number + ' වැනි'; - }, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'ප.ව.' : 'පස් වරු'; - } else { - return isLower ? 'පෙ.ව.' : 'පෙර වරු'; - } - } - }); - - //! moment.js locale configuration - //! locale : slovak (sk) - //! author : Martin Minka : https://github.com/k2s - //! based on work of petrbela : https://github.com/petrbela - - var sk__months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_'), - sk__monthsShort = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_'); - function sk__plural(n) { - return (n > 1) && (n < 5); - } - function sk__translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': // a few seconds / in a few seconds / a few seconds ago - return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami'; - case 'm': // a minute / in a minute / a minute ago - return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou'); - case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago - if (withoutSuffix || isFuture) { - return result + (sk__plural(number) ? 'minúty' : 'minút'); - } else { - return result + 'minútami'; - } - break; - case 'h': // an hour / in an hour / an hour ago - return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou'); - case 'hh': // 9 hours / in 9 hours / 9 hours ago - if (withoutSuffix || isFuture) { - return result + (sk__plural(number) ? 'hodiny' : 'hodín'); - } else { - return result + 'hodinami'; - } - break; - case 'd': // a day / in a day / a day ago - return (withoutSuffix || isFuture) ? 'deň' : 'dňom'; - case 'dd': // 9 days / in 9 days / 9 days ago - if (withoutSuffix || isFuture) { - return result + (sk__plural(number) ? 'dni' : 'dní'); - } else { - return result + 'dňami'; - } - break; - case 'M': // a month / in a month / a month ago - return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom'; - case 'MM': // 9 months / in 9 months / 9 months ago - if (withoutSuffix || isFuture) { - return result + (sk__plural(number) ? 'mesiace' : 'mesiacov'); - } else { - return result + 'mesiacmi'; - } - break; - case 'y': // a year / in a year / a year ago - return (withoutSuffix || isFuture) ? 'rok' : 'rokom'; - case 'yy': // 9 years / in 9 years / 9 years ago - if (withoutSuffix || isFuture) { - return result + (sk__plural(number) ? 'roky' : 'rokov'); - } else { - return result + 'rokmi'; - } - break; - } - } - - var sk = _moment__default.defineLocale('sk', { - months : sk__months, - monthsShort : sk__monthsShort, - monthsParse : (function (months, monthsShort) { - var i, _monthsParse = []; - for (i = 0; i < 12; i++) { - // use custom parser to solve problem with July (červenec) - _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i'); - } - return _monthsParse; - }(sk__months, sk__monthsShort)), - weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'), - weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'), - weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'), - longDateFormat : { - LT: 'H:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[dnes o] LT', - nextDay: '[zajtra o] LT', - nextWeek: function () { - switch (this.day()) { - case 0: - return '[v nedeľu o] LT'; - case 1: - case 2: - return '[v] dddd [o] LT'; - case 3: - return '[v stredu o] LT'; - case 4: - return '[vo štvrtok o] LT'; - case 5: - return '[v piatok o] LT'; - case 6: - return '[v sobotu o] LT'; - } - }, - lastDay: '[včera o] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[minulú nedeľu o] LT'; - case 1: - case 2: - return '[minulý] dddd [o] LT'; - case 3: - return '[minulú stredu o] LT'; - case 4: - case 5: - return '[minulý] dddd [o] LT'; - case 6: - return '[minulú sobotu o] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'za %s', - past : 'pred %s', - s : sk__translate, - m : sk__translate, - mm : sk__translate, - h : sk__translate, - hh : sk__translate, - d : sk__translate, - dd : sk__translate, - M : sk__translate, - MM : sk__translate, - y : sk__translate, - yy : sk__translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : slovenian (sl) - //! author : Robert Sedovšek : https://github.com/sedovsek - - function sl__processRelativeTime(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': - return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami'; - case 'm': - return withoutSuffix ? 'ena minuta' : 'eno minuto'; - case 'mm': - if (number === 1) { - result += withoutSuffix ? 'minuta' : 'minuto'; - } else if (number === 2) { - result += withoutSuffix || isFuture ? 'minuti' : 'minutama'; - } else if (number < 5) { - result += withoutSuffix || isFuture ? 'minute' : 'minutami'; - } else { - result += withoutSuffix || isFuture ? 'minut' : 'minutami'; - } - return result; - case 'h': - return withoutSuffix ? 'ena ura' : 'eno uro'; - case 'hh': - if (number === 1) { - result += withoutSuffix ? 'ura' : 'uro'; - } else if (number === 2) { - result += withoutSuffix || isFuture ? 'uri' : 'urama'; - } else if (number < 5) { - result += withoutSuffix || isFuture ? 'ure' : 'urami'; - } else { - result += withoutSuffix || isFuture ? 'ur' : 'urami'; - } - return result; - case 'd': - return withoutSuffix || isFuture ? 'en dan' : 'enim dnem'; - case 'dd': - if (number === 1) { - result += withoutSuffix || isFuture ? 'dan' : 'dnem'; - } else if (number === 2) { - result += withoutSuffix || isFuture ? 'dni' : 'dnevoma'; - } else { - result += withoutSuffix || isFuture ? 'dni' : 'dnevi'; - } - return result; - case 'M': - return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem'; - case 'MM': - if (number === 1) { - result += withoutSuffix || isFuture ? 'mesec' : 'mesecem'; - } else if (number === 2) { - result += withoutSuffix || isFuture ? 'meseca' : 'mesecema'; - } else if (number < 5) { - result += withoutSuffix || isFuture ? 'mesece' : 'meseci'; - } else { - result += withoutSuffix || isFuture ? 'mesecev' : 'meseci'; - } - return result; - case 'y': - return withoutSuffix || isFuture ? 'eno leto' : 'enim letom'; - case 'yy': - if (number === 1) { - result += withoutSuffix || isFuture ? 'leto' : 'letom'; - } else if (number === 2) { - result += withoutSuffix || isFuture ? 'leti' : 'letoma'; - } else if (number < 5) { - result += withoutSuffix || isFuture ? 'leta' : 'leti'; - } else { - result += withoutSuffix || isFuture ? 'let' : 'leti'; - } - return result; - } - } - - var sl = _moment__default.defineLocale('sl', { - months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'), - monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'), - weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'), - weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'), - weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'), - longDateFormat : { - LT : 'H:mm', - LTS : 'LT:ss', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[danes ob] LT', - nextDay : '[jutri ob] LT', - - nextWeek : function () { - switch (this.day()) { - case 0: - return '[v] [nedeljo] [ob] LT'; - case 3: - return '[v] [sredo] [ob] LT'; - case 6: - return '[v] [soboto] [ob] LT'; - case 1: - case 2: - case 4: - case 5: - return '[v] dddd [ob] LT'; - } - }, - lastDay : '[včeraj ob] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - return '[prejšnjo] [nedeljo] [ob] LT'; - case 3: - return '[prejšnjo] [sredo] [ob] LT'; - case 6: - return '[prejšnjo] [soboto] [ob] LT'; - case 1: - case 2: - case 4: - case 5: - return '[prejšnji] dddd [ob] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'čez %s', - past : 'pred %s', - s : sl__processRelativeTime, - m : sl__processRelativeTime, - mm : sl__processRelativeTime, - h : sl__processRelativeTime, - hh : sl__processRelativeTime, - d : sl__processRelativeTime, - dd : sl__processRelativeTime, - M : sl__processRelativeTime, - MM : sl__processRelativeTime, - y : sl__processRelativeTime, - yy : sl__processRelativeTime - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Albanian (sq) - //! author : Flakërim Ismani : https://github.com/flakerimi - //! author: Menelion Elensúle: https://github.com/Oire (tests) - //! author : Oerd Cukalla : https://github.com/oerd (fixes) - - var sq = _moment__default.defineLocale('sq', { - months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'), - monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'), - weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'), - weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'), - weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'), - meridiemParse: /PD|MD/, - isPM: function (input) { - return input.charAt(0) === 'M'; - }, - meridiem : function (hours, minutes, isLower) { - return hours < 12 ? 'PD' : 'MD'; - }, - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Sot në] LT', - nextDay : '[Nesër në] LT', - nextWeek : 'dddd [në] LT', - lastDay : '[Dje në] LT', - lastWeek : 'dddd [e kaluar në] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'në %s', - past : '%s më parë', - s : 'disa sekonda', - m : 'një minutë', - mm : '%d minuta', - h : 'një orë', - hh : '%d orë', - d : 'një ditë', - dd : '%d ditë', - M : 'një muaj', - MM : '%d muaj', - y : 'një vit', - yy : '%d vite' - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Serbian-cyrillic (sr-cyrl) - //! author : Milan Janačković : https://github.com/milan-j - - var sr_cyrl__translator = { - words: { //Different grammatical cases - m: ['један минут', 'једне минуте'], - mm: ['минут', 'минуте', 'минута'], - h: ['један сат', 'једног сата'], - hh: ['сат', 'сата', 'сати'], - dd: ['дан', 'дана', 'дана'], - MM: ['месец', 'месеца', 'месеци'], - yy: ['година', 'године', 'година'] - }, - correctGrammaticalCase: function (number, wordKey) { - return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]); - }, - translate: function (number, withoutSuffix, key) { - var wordKey = sr_cyrl__translator.words[key]; - if (key.length === 1) { - return withoutSuffix ? wordKey[0] : wordKey[1]; - } else { - return number + ' ' + sr_cyrl__translator.correctGrammaticalCase(number, wordKey); - } - } - }; - - var sr_cyrl = _moment__default.defineLocale('sr-cyrl', { - months: ['јануар', 'фебруар', 'март', 'април', 'мај', 'јун', 'јул', 'август', 'септембар', 'октобар', 'новембар', 'децембар'], - monthsShort: ['јан.', 'феб.', 'мар.', 'апр.', 'мај', 'јун', 'јул', 'авг.', 'сеп.', 'окт.', 'нов.', 'дец.'], - weekdays: ['недеља', 'понедељак', 'уторак', 'среда', 'четвртак', 'петак', 'субота'], - weekdaysShort: ['нед.', 'пон.', 'уто.', 'сре.', 'чет.', 'пет.', 'суб.'], - weekdaysMin: ['не', 'по', 'ут', 'ср', 'че', 'пе', 'су'], - longDateFormat: { - LT: 'H:mm', - LTS : 'LT:ss', - L: 'DD. MM. YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[данас у] LT', - nextDay: '[сутра у] LT', - nextWeek: function () { - switch (this.day()) { - case 0: - return '[у] [недељу] [у] LT'; - case 3: - return '[у] [среду] [у] LT'; - case 6: - return '[у] [суботу] [у] LT'; - case 1: - case 2: - case 4: - case 5: - return '[у] dddd [у] LT'; - } - }, - lastDay : '[јуче у] LT', - lastWeek : function () { - var lastWeekDays = [ - '[прошле] [недеље] [у] LT', - '[прошлог] [понедељка] [у] LT', - '[прошлог] [уторка] [у] LT', - '[прошле] [среде] [у] LT', - '[прошлог] [четвртка] [у] LT', - '[прошлог] [петка] [у] LT', - '[прошле] [суботе] [у] LT' - ]; - return lastWeekDays[this.day()]; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'за %s', - past : 'пре %s', - s : 'неколико секунди', - m : sr_cyrl__translator.translate, - mm : sr_cyrl__translator.translate, - h : sr_cyrl__translator.translate, - hh : sr_cyrl__translator.translate, - d : 'дан', - dd : sr_cyrl__translator.translate, - M : 'месец', - MM : sr_cyrl__translator.translate, - y : 'годину', - yy : sr_cyrl__translator.translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Serbian-latin (sr) - //! author : Milan Janačković : https://github.com/milan-j - - var sr__translator = { - words: { //Different grammatical cases - m: ['jedan minut', 'jedne minute'], - mm: ['minut', 'minute', 'minuta'], - h: ['jedan sat', 'jednog sata'], - hh: ['sat', 'sata', 'sati'], - dd: ['dan', 'dana', 'dana'], - MM: ['mesec', 'meseca', 'meseci'], - yy: ['godina', 'godine', 'godina'] - }, - correctGrammaticalCase: function (number, wordKey) { - return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]); - }, - translate: function (number, withoutSuffix, key) { - var wordKey = sr__translator.words[key]; - if (key.length === 1) { - return withoutSuffix ? wordKey[0] : wordKey[1]; - } else { - return number + ' ' + sr__translator.correctGrammaticalCase(number, wordKey); - } - } - }; - - var sr = _moment__default.defineLocale('sr', { - months: ['januar', 'februar', 'mart', 'april', 'maj', 'jun', 'jul', 'avgust', 'septembar', 'oktobar', 'novembar', 'decembar'], - monthsShort: ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun', 'jul', 'avg.', 'sep.', 'okt.', 'nov.', 'dec.'], - weekdays: ['nedelja', 'ponedeljak', 'utorak', 'sreda', 'četvrtak', 'petak', 'subota'], - weekdaysShort: ['ned.', 'pon.', 'uto.', 'sre.', 'čet.', 'pet.', 'sub.'], - weekdaysMin: ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'], - longDateFormat: { - LT: 'H:mm', - LTS : 'LT:ss', - L: 'DD. MM. YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[danas u] LT', - nextDay: '[sutra u] LT', - nextWeek: function () { - switch (this.day()) { - case 0: - return '[u] [nedelju] [u] LT'; - case 3: - return '[u] [sredu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[juče u] LT', - lastWeek : function () { - var lastWeekDays = [ - '[prošle] [nedelje] [u] LT', - '[prošlog] [ponedeljka] [u] LT', - '[prošlog] [utorka] [u] LT', - '[prošle] [srede] [u] LT', - '[prošlog] [četvrtka] [u] LT', - '[prošlog] [petka] [u] LT', - '[prošle] [subote] [u] LT' - ]; - return lastWeekDays[this.day()]; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'pre %s', - s : 'nekoliko sekundi', - m : sr__translator.translate, - mm : sr__translator.translate, - h : sr__translator.translate, - hh : sr__translator.translate, - d : 'dan', - dd : sr__translator.translate, - M : 'mesec', - MM : sr__translator.translate, - y : 'godinu', - yy : sr__translator.translate - }, - ordinalParse: /\d{1,2}\./, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : swedish (sv) - //! author : Jens Alm : https://github.com/ulmus - - var sv = _moment__default.defineLocale('sv', { - months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), - weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'), - weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'), - weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'YYYY-MM-DD', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Idag] LT', - nextDay: '[Imorgon] LT', - lastDay: '[Igår] LT', - nextWeek: '[På] dddd LT', - lastWeek: '[I] dddd[s] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'om %s', - past : 'för %s sedan', - s : 'några sekunder', - m : 'en minut', - mm : '%d minuter', - h : 'en timme', - hh : '%d timmar', - d : 'en dag', - dd : '%d dagar', - M : 'en månad', - MM : '%d månader', - y : 'ett år', - yy : '%d år' - }, - ordinalParse: /\d{1,2}(e|a)/, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'e' : - (b === 1) ? 'a' : - (b === 2) ? 'a' : - (b === 3) ? 'e' : 'e'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : tamil (ta) - //! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404 - - var ta = _moment__default.defineLocale('ta', { - months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'), - monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'), - weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'), - weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'), - weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[இன்று] LT', - nextDay : '[நாளை] LT', - nextWeek : 'dddd, LT', - lastDay : '[நேற்று] LT', - lastWeek : '[கடந்த வாரம்] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s இல்', - past : '%s முன்', - s : 'ஒரு சில விநாடிகள்', - m : 'ஒரு நிமிடம்', - mm : '%d நிமிடங்கள்', - h : 'ஒரு மணி நேரம்', - hh : '%d மணி நேரம்', - d : 'ஒரு நாள்', - dd : '%d நாட்கள்', - M : 'ஒரு மாதம்', - MM : '%d மாதங்கள்', - y : 'ஒரு வருடம்', - yy : '%d ஆண்டுகள்' - }, - ordinalParse: /\d{1,2}வது/, - ordinal : function (number) { - return number + 'வது'; - }, - // refer http://ta.wikipedia.org/s/1er1 - meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/, - meridiem : function (hour, minute, isLower) { - if (hour < 2) { - return ' யாமம்'; - } else if (hour < 6) { - return ' வைகறை'; // வைகறை - } else if (hour < 10) { - return ' காலை'; // காலை - } else if (hour < 14) { - return ' நண்பகல்'; // நண்பகல் - } else if (hour < 18) { - return ' எற்பாடு'; // எற்பாடு - } else if (hour < 22) { - return ' மாலை'; // மாலை - } else { - return ' யாமம்'; - } - }, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === 'யாமம்') { - return hour < 2 ? hour : hour + 12; - } else if (meridiem === 'வைகறை' || meridiem === 'காலை') { - return hour; - } else if (meridiem === 'நண்பகல்') { - return hour >= 10 ? hour : hour + 12; - } else { - return hour + 12; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : thai (th) - //! author : Kridsada Thanabulpong : https://github.com/sirn - - var th = _moment__default.defineLocale('th', { - months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'), - monthsShort : 'มกรา_กุมภา_มีนา_เมษา_พฤษภา_มิถุนา_กรกฎา_สิงหา_กันยา_ตุลา_พฤศจิกา_ธันวา'.split('_'), - weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'), - weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference - weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'), - longDateFormat : { - LT : 'H นาฬิกา m นาที', - LTS : 'LT s วินาที', - L : 'YYYY/MM/DD', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY เวลา LT', - LLLL : 'วันddddที่ D MMMM YYYY เวลา LT' - }, - meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/, - isPM: function (input) { - return input === 'หลังเที่ยง'; - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'ก่อนเที่ยง'; - } else { - return 'หลังเที่ยง'; - } - }, - calendar : { - sameDay : '[วันนี้ เวลา] LT', - nextDay : '[พรุ่งนี้ เวลา] LT', - nextWeek : 'dddd[หน้า เวลา] LT', - lastDay : '[เมื่อวานนี้ เวลา] LT', - lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'อีก %s', - past : '%sที่แล้ว', - s : 'ไม่กี่วินาที', - m : '1 นาที', - mm : '%d นาที', - h : '1 ชั่วโมง', - hh : '%d ชั่วโมง', - d : '1 วัน', - dd : '%d วัน', - M : '1 เดือน', - MM : '%d เดือน', - y : '1 ปี', - yy : '%d ปี' - } - }); - - //! moment.js locale configuration - //! locale : Tagalog/Filipino (tl-ph) - //! author : Dan Hagman - - var tl_ph = _moment__default.defineLocale('tl-ph', { - months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'), - monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'), - weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'), - weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'), - weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'MM/D/YYYY', - LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM DD, YYYY LT' - }, - calendar : { - sameDay: '[Ngayon sa] LT', - nextDay: '[Bukas sa] LT', - nextWeek: 'dddd [sa] LT', - lastDay: '[Kahapon sa] LT', - lastWeek: 'dddd [huling linggo] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'sa loob ng %s', - past : '%s ang nakalipas', - s : 'ilang segundo', - m : 'isang minuto', - mm : '%d minuto', - h : 'isang oras', - hh : '%d oras', - d : 'isang araw', - dd : '%d araw', - M : 'isang buwan', - MM : '%d buwan', - y : 'isang taon', - yy : '%d taon' - }, - ordinalParse: /\d{1,2}/, - ordinal : function (number) { - return number; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : turkish (tr) - //! authors : Erhan Gundogan : https://github.com/erhangundogan, - //! Burak Yiğit Kaya: https://github.com/BYK - - var tr__suffixes = { - 1: '\'inci', - 5: '\'inci', - 8: '\'inci', - 70: '\'inci', - 80: '\'inci', - 2: '\'nci', - 7: '\'nci', - 20: '\'nci', - 50: '\'nci', - 3: '\'üncü', - 4: '\'üncü', - 100: '\'üncü', - 6: '\'ncı', - 9: '\'uncu', - 10: '\'uncu', - 30: '\'uncu', - 60: '\'ıncı', - 90: '\'ıncı' - }; - - var tr = _moment__default.defineLocale('tr', { - months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'), - monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'), - weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'), - weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'), - weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[bugün saat] LT', - nextDay : '[yarın saat] LT', - nextWeek : '[haftaya] dddd [saat] LT', - lastDay : '[dün] LT', - lastWeek : '[geçen hafta] dddd [saat] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s sonra', - past : '%s önce', - s : 'birkaç saniye', - m : 'bir dakika', - mm : '%d dakika', - h : 'bir saat', - hh : '%d saat', - d : 'bir gün', - dd : '%d gün', - M : 'bir ay', - MM : '%d ay', - y : 'bir yıl', - yy : '%d yıl' - }, - ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/, - ordinal : function (number) { - if (number === 0) { // special case for zero - return number + '\'ıncı'; - } - var a = number % 10, - b = number % 100 - a, - c = number >= 100 ? 100 : null; - return number + (tr__suffixes[a] || tr__suffixes[b] || tr__suffixes[c]); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Morocco Central Atlas Tamaziɣt in Latin (tzm-latn) - //! author : Abdel Said : https://github.com/abdelsaid - - var tzm_latn = _moment__default.defineLocale('tzm-latn', { - months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'), - monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'), - weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), - weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), - weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[asdkh g] LT', - nextDay: '[aska g] LT', - nextWeek: 'dddd [g] LT', - lastDay: '[assant g] LT', - lastWeek: 'dddd [g] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'dadkh s yan %s', - past : 'yan %s', - s : 'imik', - m : 'minuḍ', - mm : '%d minuḍ', - h : 'saɛa', - hh : '%d tassaɛin', - d : 'ass', - dd : '%d ossan', - M : 'ayowr', - MM : '%d iyyirn', - y : 'asgas', - yy : '%d isgasn' - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : Morocco Central Atlas Tamaziɣt (tzm) - //! author : Abdel Said : https://github.com/abdelsaid - - var tzm = _moment__default.defineLocale('tzm', { - months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'), - monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'), - weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), - weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), - weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS: 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[ⴰⵙⴷⵅ ⴴ] LT', - nextDay: '[ⴰⵙⴽⴰ ⴴ] LT', - nextWeek: 'dddd [ⴴ] LT', - lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT', - lastWeek: 'dddd [ⴴ] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s', - past : 'ⵢⴰⵏ %s', - s : 'ⵉⵎⵉⴽ', - m : 'ⵎⵉⵏⵓⴺ', - mm : '%d ⵎⵉⵏⵓⴺ', - h : 'ⵙⴰⵄⴰ', - hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ', - d : 'ⴰⵙⵙ', - dd : '%d oⵙⵙⴰⵏ', - M : 'ⴰⵢoⵓⵔ', - MM : '%d ⵉⵢⵢⵉⵔⵏ', - y : 'ⴰⵙⴳⴰⵙ', - yy : '%d ⵉⵙⴳⴰⵙⵏ' - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : ukrainian (uk) - //! author : zemlanin : https://github.com/zemlanin - //! Author : Menelion Elensúle : https://github.com/Oire - - function uk__plural(word, num) { - var forms = word.split('_'); - return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); - } - function uk__relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': 'хвилина_хвилини_хвилин', - 'hh': 'година_години_годин', - 'dd': 'день_дні_днів', - 'MM': 'місяць_місяці_місяців', - 'yy': 'рік_роки_років' - }; - if (key === 'm') { - return withoutSuffix ? 'хвилина' : 'хвилину'; - } - else if (key === 'h') { - return withoutSuffix ? 'година' : 'годину'; - } - else { - return number + ' ' + uk__plural(format[key], +number); - } - } - function uk__monthsCaseReplace(m, format) { - var months = { - 'nominative': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_'), - 'accusative': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_') - }, - nounCase = (/D[oD]? *MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - return months[nounCase][m.month()]; - } - function uk__weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'), - 'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'), - 'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_') - }, - nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ? - 'accusative' : - ((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ? - 'genitive' : - 'nominative'); - return weekdays[nounCase][m.day()]; - } - function processHoursFunction(str) { - return function () { - return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT'; - }; - } - - var uk = _moment__default.defineLocale('uk', { - months : uk__monthsCaseReplace, - monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'), - weekdays : uk__weekdaysCaseReplace, - weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), - weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY р.', - LLL : 'D MMMM YYYY р., LT', - LLLL : 'dddd, D MMMM YYYY р., LT' - }, - calendar : { - sameDay: processHoursFunction('[Сьогодні '), - nextDay: processHoursFunction('[Завтра '), - lastDay: processHoursFunction('[Вчора '), - nextWeek: processHoursFunction('[У] dddd ['), - lastWeek: function () { - switch (this.day()) { - case 0: - case 3: - case 5: - case 6: - return processHoursFunction('[Минулої] dddd [').call(this); - case 1: - case 2: - case 4: - return processHoursFunction('[Минулого] dddd [').call(this); - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'за %s', - past : '%s тому', - s : 'декілька секунд', - m : uk__relativeTimeWithPlural, - mm : uk__relativeTimeWithPlural, - h : 'годину', - hh : uk__relativeTimeWithPlural, - d : 'день', - dd : uk__relativeTimeWithPlural, - M : 'місяць', - MM : uk__relativeTimeWithPlural, - y : 'рік', - yy : uk__relativeTimeWithPlural - }, - // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason - meridiemParse: /ночі|ранку|дня|вечора/, - isPM: function (input) { - return /^(дня|вечора)$/.test(input); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'ночі'; - } else if (hour < 12) { - return 'ранку'; - } else if (hour < 17) { - return 'дня'; - } else { - return 'вечора'; - } - }, - ordinalParse: /\d{1,2}-(й|го)/, - ordinal: function (number, period) { - switch (period) { - case 'M': - case 'd': - case 'DDD': - case 'w': - case 'W': - return number + '-й'; - case 'D': - return number + '-го'; - default: - return number; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : uzbek (uz) - //! author : Sardor Muminov : https://github.com/muminoff - - var uz = _moment__default.defineLocale('uz', { - months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'), - monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'), - weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'), - weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'), - weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'D MMMM YYYY, dddd LT' - }, - calendar : { - sameDay : '[Бугун соат] LT [да]', - nextDay : '[Эртага] LT [да]', - nextWeek : 'dddd [куни соат] LT [да]', - lastDay : '[Кеча соат] LT [да]', - lastWeek : '[Утган] dddd [куни соат] LT [да]', - sameElse : 'L' - }, - relativeTime : { - future : 'Якин %s ичида', - past : 'Бир неча %s олдин', - s : 'фурсат', - m : 'бир дакика', - mm : '%d дакика', - h : 'бир соат', - hh : '%d соат', - d : 'бир кун', - dd : '%d кун', - M : 'бир ой', - MM : '%d ой', - y : 'бир йил', - yy : '%d йил' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : vietnamese (vi) - //! author : Bang Nguyen : https://github.com/bangnk - - var vi = _moment__default.defineLocale('vi', { - months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'), - monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'), - weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'), - weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'), - weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'), - longDateFormat : { - LT : 'HH:mm', - LTS : 'LT:ss', - L : 'DD/MM/YYYY', - LL : 'D MMMM [năm] YYYY', - LLL : 'D MMMM [năm] YYYY LT', - LLLL : 'dddd, D MMMM [năm] YYYY LT', - l : 'DD/M/YYYY', - ll : 'D MMM YYYY', - lll : 'D MMM YYYY LT', - llll : 'ddd, D MMM YYYY LT' - }, - calendar : { - sameDay: '[Hôm nay lúc] LT', - nextDay: '[Ngày mai lúc] LT', - nextWeek: 'dddd [tuần tới lúc] LT', - lastDay: '[Hôm qua lúc] LT', - lastWeek: 'dddd [tuần rồi lúc] LT', - sameElse: 'L' - }, - relativeTime : { - future : '%s tới', - past : '%s trước', - s : 'vài giây', - m : 'một phút', - mm : '%d phút', - h : 'một giờ', - hh : '%d giờ', - d : 'một ngày', - dd : '%d ngày', - M : 'một tháng', - MM : '%d tháng', - y : 'một năm', - yy : '%d năm' - }, - ordinalParse: /\d{1,2}/, - ordinal : function (number) { - return number; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : chinese (zh-cn) - //! author : suupic : https://github.com/suupic - //! author : Zeno Zeng : https://github.com/zenozeng - - var zh_cn = _moment__default.defineLocale('zh-cn', { - months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), - monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), - weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'), - weekdaysMin : '日_一_二_三_四_五_六'.split('_'), - longDateFormat : { - LT : 'Ah点mm分', - LTS : 'Ah点m分s秒', - L : 'YYYY-MM-DD', - LL : 'YYYY年MMMD日', - LLL : 'YYYY年MMMD日LT', - LLLL : 'YYYY年MMMD日ddddLT', - l : 'YYYY-MM-DD', - ll : 'YYYY年MMMD日', - lll : 'YYYY年MMMD日LT', - llll : 'YYYY年MMMD日ddddLT' - }, - meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, - meridiemHour: function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === '凌晨' || meridiem === '早上' || - meridiem === '上午') { - return hour; - } else if (meridiem === '下午' || meridiem === '晚上') { - return hour + 12; - } else { - // '中午' - return hour >= 11 ? hour : hour + 12; - } - }, - meridiem : function (hour, minute, isLower) { - var hm = hour * 100 + minute; - if (hm < 600) { - return '凌晨'; - } else if (hm < 900) { - return '早上'; - } else if (hm < 1130) { - return '上午'; - } else if (hm < 1230) { - return '中午'; - } else if (hm < 1800) { - return '下午'; - } else { - return '晚上'; - } - }, - calendar : { - sameDay : function () { - return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT'; - }, - nextDay : function () { - return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT'; - }, - lastDay : function () { - return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT'; - }, - nextWeek : function () { - var startOfWeek, prefix; - startOfWeek = _moment__default().startOf('week'); - prefix = this.unix() - startOfWeek.unix() >= 7 * 24 * 3600 ? '[下]' : '[本]'; - return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm'; - }, - lastWeek : function () { - var startOfWeek, prefix; - startOfWeek = _moment__default().startOf('week'); - prefix = this.unix() < startOfWeek.unix() ? '[上]' : '[本]'; - return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm'; - }, - sameElse : 'LL' - }, - ordinalParse: /\d{1,2}(日|月|周)/, - ordinal : function (number, period) { - switch (period) { - case 'd': - case 'D': - case 'DDD': - return number + '日'; - case 'M': - return number + '月'; - case 'w': - case 'W': - return number + '周'; - default: - return number; - } - }, - relativeTime : { - future : '%s内', - past : '%s前', - s : '几秒', - m : '1 分钟', - mm : '%d 分钟', - h : '1 小时', - hh : '%d 小时', - d : '1 天', - dd : '%d 天', - M : '1 个月', - MM : '%d 个月', - y : '1 年', - yy : '%d 年' - }, - week : { - // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); - - //! moment.js locale configuration - //! locale : traditional chinese (zh-tw) - //! author : Ben : https://github.com/ben-lin - - var zh_tw = _moment__default.defineLocale('zh-tw', { - months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), - monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), - weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'), - weekdaysMin : '日_一_二_三_四_五_六'.split('_'), - longDateFormat : { - LT : 'Ah點mm分', - LTS : 'Ah點m分s秒', - L : 'YYYY年MMMD日', - LL : 'YYYY年MMMD日', - LLL : 'YYYY年MMMD日LT', - LLLL : 'YYYY年MMMD日ddddLT', - l : 'YYYY年MMMD日', - ll : 'YYYY年MMMD日', - lll : 'YYYY年MMMD日LT', - llll : 'YYYY年MMMD日ddddLT' - }, - meridiemParse: /早上|上午|中午|下午|晚上/, - meridiemHour : function (hour, meridiem) { - if (hour === 12) { - hour = 0; - } - if (meridiem === '早上' || meridiem === '上午') { - return hour; - } else if (meridiem === '中午') { - return hour >= 11 ? hour : hour + 12; - } else if (meridiem === '下午' || meridiem === '晚上') { - return hour + 12; - } - }, - meridiem : function (hour, minute, isLower) { - var hm = hour * 100 + minute; - if (hm < 900) { - return '早上'; - } else if (hm < 1130) { - return '上午'; - } else if (hm < 1230) { - return '中午'; - } else if (hm < 1800) { - return '下午'; - } else { - return '晚上'; - } - }, - calendar : { - sameDay : '[今天]LT', - nextDay : '[明天]LT', - nextWeek : '[下]ddddLT', - lastDay : '[昨天]LT', - lastWeek : '[上]ddddLT', - sameElse : 'L' - }, - ordinalParse: /\d{1,2}(日|月|週)/, - ordinal : function (number, period) { - switch (period) { - case 'd' : - case 'D' : - case 'DDD' : - return number + '日'; - case 'M' : - return number + '月'; - case 'w' : - case 'W' : - return number + '週'; - default : - return number; - } - }, - relativeTime : { - future : '%s內', - past : '%s前', - s : '幾秒', - m : '一分鐘', - mm : '%d分鐘', - h : '一小時', - hh : '%d小時', - d : '一天', - dd : '%d天', - M : '一個月', - MM : '%d個月', - y : '一年', - yy : '%d年' - } - }); - - var moment_with_locales = _moment__default; - - return moment_with_locales; - -})); -/** - * State-based routing for AngularJS - * @version v0.2.13 - * @link http://angular-ui.github.com/ - * @license MIT License, http://www.opensource.org/licenses/MIT - */ - -/* commonjs package manager support (eg componentjs) */ -if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){ - module.exports = 'ui.router'; -} - -(function (window, angular, undefined) { -/*jshint globalstrict:true*/ -/*global angular:false*/ -'use strict'; - -var isDefined = angular.isDefined, - isFunction = angular.isFunction, - isString = angular.isString, - isObject = angular.isObject, - isArray = angular.isArray, - forEach = angular.forEach, - extend = angular.extend, - copy = angular.copy; - -function inherit(parent, extra) { - return extend(new (extend(function() {}, { prototype: parent }))(), extra); -} - -function merge(dst) { - forEach(arguments, function(obj) { - if (obj !== dst) { - forEach(obj, function(value, key) { - if (!dst.hasOwnProperty(key)) dst[key] = value; - }); - } - }); - return dst; -} - -/** - * Finds the common ancestor path between two states. - * - * @param {Object} first The first state. - * @param {Object} second The second state. - * @return {Array} Returns an array of state names in descending order, not including the root. - */ -function ancestors(first, second) { - var path = []; - - for (var n in first.path) { - if (first.path[n] !== second.path[n]) break; - path.push(first.path[n]); - } - return path; -} - -/** - * IE8-safe wrapper for `Object.keys()`. - * - * @param {Object} object A JavaScript object. - * @return {Array} Returns the keys of the object as an array. - */ -function objectKeys(object) { - if (Object.keys) { - return Object.keys(object); - } - var result = []; - - angular.forEach(object, function(val, key) { - result.push(key); - }); - return result; -} - -/** - * IE8-safe wrapper for `Array.prototype.indexOf()`. - * - * @param {Array} array A JavaScript array. - * @param {*} value A value to search the array for. - * @return {Number} Returns the array index value of `value`, or `-1` if not present. - */ -function indexOf(array, value) { - if (Array.prototype.indexOf) { - return array.indexOf(value, Number(arguments[2]) || 0); - } - var len = array.length >>> 0, from = Number(arguments[2]) || 0; - from = (from < 0) ? Math.ceil(from) : Math.floor(from); - - if (from < 0) from += len; - - for (; from < len; from++) { - if (from in array && array[from] === value) return from; - } - return -1; -} - -/** - * Merges a set of parameters with all parameters inherited between the common parents of the - * current state and a given destination state. - * - * @param {Object} currentParams The value of the current state parameters ($stateParams). - * @param {Object} newParams The set of parameters which will be composited with inherited params. - * @param {Object} $current Internal definition of object representing the current state. - * @param {Object} $to Internal definition of object representing state to transition to. - */ -function inheritParams(currentParams, newParams, $current, $to) { - var parents = ancestors($current, $to), parentParams, inherited = {}, inheritList = []; - - for (var i in parents) { - if (!parents[i].params) continue; - parentParams = objectKeys(parents[i].params); - if (!parentParams.length) continue; - - for (var j in parentParams) { - if (indexOf(inheritList, parentParams[j]) >= 0) continue; - inheritList.push(parentParams[j]); - inherited[parentParams[j]] = currentParams[parentParams[j]]; - } - } - return extend({}, inherited, newParams); -} - -/** - * Performs a non-strict comparison of the subset of two objects, defined by a list of keys. - * - * @param {Object} a The first object. - * @param {Object} b The second object. - * @param {Array} keys The list of keys within each object to compare. If the list is empty or not specified, - * it defaults to the list of keys in `a`. - * @return {Boolean} Returns `true` if the keys match, otherwise `false`. - */ -function equalForKeys(a, b, keys) { - if (!keys) { - keys = []; - for (var n in a) keys.push(n); // Used instead of Object.keys() for IE8 compatibility - } - - for (var i=0; i - * - * - * - * - * - * - * - * - * - * - * - * - */ -angular.module('ui.router', ['ui.router.state']); - -angular.module('ui.router.compat', ['ui.router']); - -/** - * @ngdoc object - * @name ui.router.util.$resolve - * - * @requires $q - * @requires $injector - * - * @description - * Manages resolution of (acyclic) graphs of promises. - */ -$Resolve.$inject = ['$q', '$injector']; -function $Resolve( $q, $injector) { - - var VISIT_IN_PROGRESS = 1, - VISIT_DONE = 2, - NOTHING = {}, - NO_DEPENDENCIES = [], - NO_LOCALS = NOTHING, - NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING }); - - - /** - * @ngdoc function - * @name ui.router.util.$resolve#study - * @methodOf ui.router.util.$resolve - * - * @description - * Studies a set of invocables that are likely to be used multiple times. - *
-   * $resolve.study(invocables)(locals, parent, self)
-   * 
- * is equivalent to - *
-   * $resolve.resolve(invocables, locals, parent, self)
-   * 
- * but the former is more efficient (in fact `resolve` just calls `study` - * internally). - * - * @param {object} invocables Invocable objects - * @return {function} a function to pass in locals, parent and self - */ - this.study = function (invocables) { - if (!isObject(invocables)) throw new Error("'invocables' must be an object"); - var invocableKeys = objectKeys(invocables || {}); - - // Perform a topological sort of invocables to build an ordered plan - var plan = [], cycle = [], visited = {}; - function visit(value, key) { - if (visited[key] === VISIT_DONE) return; - - cycle.push(key); - if (visited[key] === VISIT_IN_PROGRESS) { - cycle.splice(0, indexOf(cycle, key)); - throw new Error("Cyclic dependency: " + cycle.join(" -> ")); - } - visited[key] = VISIT_IN_PROGRESS; - - if (isString(value)) { - plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES); - } else { - var params = $injector.annotate(value); - forEach(params, function (param) { - if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param); - }); - plan.push(key, value, params); - } - - cycle.pop(); - visited[key] = VISIT_DONE; - } - forEach(invocables, visit); - invocables = cycle = visited = null; // plan is all that's required - - function isResolve(value) { - return isObject(value) && value.then && value.$$promises; - } - - return function (locals, parent, self) { - if (isResolve(locals) && self === undefined) { - self = parent; parent = locals; locals = null; - } - if (!locals) locals = NO_LOCALS; - else if (!isObject(locals)) { - throw new Error("'locals' must be an object"); - } - if (!parent) parent = NO_PARENT; - else if (!isResolve(parent)) { - throw new Error("'parent' must be a promise returned by $resolve.resolve()"); - } - - // To complete the overall resolution, we have to wait for the parent - // promise and for the promise for each invokable in our plan. - var resolution = $q.defer(), - result = resolution.promise, - promises = result.$$promises = {}, - values = extend({}, locals), - wait = 1 + plan.length/3, - merged = false; - - function done() { - // Merge parent values we haven't got yet and publish our own $$values - if (!--wait) { - if (!merged) merge(values, parent.$$values); - result.$$values = values; - result.$$promises = result.$$promises || true; // keep for isResolve() - delete result.$$inheritedValues; - resolution.resolve(values); - } - } - - function fail(reason) { - result.$$failure = reason; - resolution.reject(reason); - } - - // Short-circuit if parent has already failed - if (isDefined(parent.$$failure)) { - fail(parent.$$failure); - return result; - } - - if (parent.$$inheritedValues) { - merge(values, omit(parent.$$inheritedValues, invocableKeys)); - } - - // Merge parent values if the parent has already resolved, or merge - // parent promises and wait if the parent resolve is still in progress. - extend(promises, parent.$$promises); - if (parent.$$values) { - merged = merge(values, omit(parent.$$values, invocableKeys)); - result.$$inheritedValues = omit(parent.$$values, invocableKeys); - done(); - } else { - if (parent.$$inheritedValues) { - result.$$inheritedValues = omit(parent.$$inheritedValues, invocableKeys); - } - parent.then(done, fail); - } - - // Process each invocable in the plan, but ignore any where a local of the same name exists. - for (var i=0, ii=plan.length; i} The template html as a string, or a promise - * for that string. - */ - this.fromUrl = function (url, params) { - if (isFunction(url)) url = url(params); - if (url == null) return null; - else return $http - .get(url, { cache: $templateCache, headers: { Accept: 'text/html' }}) - .then(function(response) { return response.data; }); - }; - - /** - * @ngdoc function - * @name ui.router.util.$templateFactory#fromProvider - * @methodOf ui.router.util.$templateFactory - * - * @description - * Creates a template by invoking an injectable provider function. - * - * @param {Function} provider Function to invoke via `$injector.invoke` - * @param {Object} params Parameters for the template. - * @param {Object} locals Locals to pass to `invoke`. Defaults to - * `{ params: params }`. - * @return {string|Promise.} The template html as a string, or a promise - * for that string. - */ - this.fromProvider = function (provider, params, locals) { - return $injector.invoke(provider, null, locals || { params: params }); - }; -} - -angular.module('ui.router.util').service('$templateFactory', $TemplateFactory); - -var $$UMFP; // reference to $UrlMatcherFactoryProvider - -/** - * @ngdoc object - * @name ui.router.util.type:UrlMatcher - * - * @description - * Matches URLs against patterns and extracts named parameters from the path or the search - * part of the URL. A URL pattern consists of a path pattern, optionally followed by '?' and a list - * of search parameters. Multiple search parameter names are separated by '&'. Search parameters - * do not influence whether or not a URL is matched, but their values are passed through into - * the matched parameters returned by {@link ui.router.util.type:UrlMatcher#methods_exec exec}. - * - * Path parameter placeholders can be specified using simple colon/catch-all syntax or curly brace - * syntax, which optionally allows a regular expression for the parameter to be specified: - * - * * `':'` name - colon placeholder - * * `'*'` name - catch-all placeholder - * * `'{' name '}'` - curly placeholder - * * `'{' name ':' regexp|type '}'` - curly placeholder with regexp or type name. Should the - * regexp itself contain curly braces, they must be in matched pairs or escaped with a backslash. - * - * Parameter names may contain only word characters (latin letters, digits, and underscore) and - * must be unique within the pattern (across both path and search parameters). For colon - * placeholders or curly placeholders without an explicit regexp, a path parameter matches any - * number of characters other than '/'. For catch-all placeholders the path parameter matches - * any number of characters. - * - * Examples: - * - * * `'/hello/'` - Matches only if the path is exactly '/hello/'. There is no special treatment for - * trailing slashes, and patterns have to match the entire path, not just a prefix. - * * `'/user/:id'` - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or - * '/user/bob/details'. The second path segment will be captured as the parameter 'id'. - * * `'/user/{id}'` - Same as the previous example, but using curly brace syntax. - * * `'/user/{id:[^/]*}'` - Same as the previous example. - * * `'/user/{id:[0-9a-fA-F]{1,8}}'` - Similar to the previous example, but only matches if the id - * parameter consists of 1 to 8 hex digits. - * * `'/files/{path:.*}'` - Matches any URL starting with '/files/' and captures the rest of the - * path into the parameter 'path'. - * * `'/files/*path'` - ditto. - * * `'/calendar/{start:date}'` - Matches "/calendar/2014-11-12" (because the pattern defined - * in the built-in `date` Type matches `2014-11-12`) and provides a Date object in $stateParams.start - * - * @param {string} pattern The pattern to compile into a matcher. - * @param {Object} config A configuration object hash: - * @param {Object=} parentMatcher Used to concatenate the pattern/config onto - * an existing UrlMatcher - * - * * `caseInsensitive` - `true` if URL matching should be case insensitive, otherwise `false`, the default value (for backward compatibility) is `false`. - * * `strict` - `false` if matching against a URL with a trailing slash should be treated as equivalent to a URL without a trailing slash, the default value is `true`. - * - * @property {string} prefix A static prefix of this pattern. The matcher guarantees that any - * URL matching this matcher (i.e. any string for which {@link ui.router.util.type:UrlMatcher#methods_exec exec()} returns - * non-null) will start with this prefix. - * - * @property {string} source The pattern that was passed into the constructor - * - * @property {string} sourcePath The path portion of the source property - * - * @property {string} sourceSearch The search portion of the source property - * - * @property {string} regex The constructed regex that will be used to match against the url when - * it is time to determine which url will match. - * - * @returns {Object} New `UrlMatcher` object - */ -function UrlMatcher(pattern, config, parentMatcher) { - config = extend({ params: {} }, isObject(config) ? config : {}); - - // Find all placeholders and create a compiled pattern, using either classic or curly syntax: - // '*' name - // ':' name - // '{' name '}' - // '{' name ':' regexp '}' - // The regular expression is somewhat complicated due to the need to allow curly braces - // inside the regular expression. The placeholder regexp breaks down as follows: - // ([:*])([\w\[\]]+) - classic placeholder ($1 / $2) (search version has - for snake-case) - // \{([\w\[\]]+)(?:\:( ... ))?\} - curly brace placeholder ($3) with optional regexp/type ... ($4) (search version has - for snake-case - // (?: ... | ... | ... )+ - the regexp consists of any number of atoms, an atom being either - // [^{}\\]+ - anything other than curly braces or backslash - // \\. - a backslash escape - // \{(?:[^{}\\]+|\\.)*\} - a matched set of curly braces containing other atoms - var placeholder = /([:*])([\w\[\]]+)|\{([\w\[\]]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g, - searchPlaceholder = /([:]?)([\w\[\]-]+)|\{([\w\[\]-]+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g, - compiled = '^', last = 0, m, - segments = this.segments = [], - parentParams = parentMatcher ? parentMatcher.params : {}, - params = this.params = parentMatcher ? parentMatcher.params.$$new() : new $$UMFP.ParamSet(), - paramNames = []; - - function addParameter(id, type, config, location) { - paramNames.push(id); - if (parentParams[id]) return parentParams[id]; - if (!/^\w+(-+\w+)*(?:\[\])?$/.test(id)) throw new Error("Invalid parameter name '" + id + "' in pattern '" + pattern + "'"); - if (params[id]) throw new Error("Duplicate parameter name '" + id + "' in pattern '" + pattern + "'"); - params[id] = new $$UMFP.Param(id, type, config, location); - return params[id]; - } - - function quoteRegExp(string, pattern, squash) { - var surroundPattern = ['',''], result = string.replace(/[\\\[\]\^$*+?.()|{}]/g, "\\$&"); - if (!pattern) return result; - switch(squash) { - case false: surroundPattern = ['(', ')']; break; - case true: surroundPattern = ['?(', ')?']; break; - default: surroundPattern = ['(' + squash + "|", ')?']; break; - } - return result + surroundPattern[0] + pattern + surroundPattern[1]; - } - - this.source = pattern; - - // Split into static segments separated by path parameter placeholders. - // The number of segments is always 1 more than the number of parameters. - function matchDetails(m, isSearch) { - var id, regexp, segment, type, cfg, arrayMode; - id = m[2] || m[3]; // IE[78] returns '' for unmatched groups instead of null - cfg = config.params[id]; - segment = pattern.substring(last, m.index); - regexp = isSearch ? m[4] : m[4] || (m[1] == '*' ? '.*' : null); - type = $$UMFP.type(regexp || "string") || inherit($$UMFP.type("string"), { pattern: new RegExp(regexp) }); - return { - id: id, regexp: regexp, segment: segment, type: type, cfg: cfg - }; - } - - var p, param, segment; - while ((m = placeholder.exec(pattern))) { - p = matchDetails(m, false); - if (p.segment.indexOf('?') >= 0) break; // we're into the search part - - param = addParameter(p.id, p.type, p.cfg, "path"); - compiled += quoteRegExp(p.segment, param.type.pattern.source, param.squash); - segments.push(p.segment); - last = placeholder.lastIndex; - } - segment = pattern.substring(last); - - // Find any search parameter names and remove them from the last segment - var i = segment.indexOf('?'); - - if (i >= 0) { - var search = this.sourceSearch = segment.substring(i); - segment = segment.substring(0, i); - this.sourcePath = pattern.substring(0, last + i); - - if (search.length > 0) { - last = 0; - while ((m = searchPlaceholder.exec(search))) { - p = matchDetails(m, true); - param = addParameter(p.id, p.type, p.cfg, "search"); - last = placeholder.lastIndex; - // check if ?& - } - } - } else { - this.sourcePath = pattern; - this.sourceSearch = ''; - } - - compiled += quoteRegExp(segment) + (config.strict === false ? '\/?' : '') + '$'; - segments.push(segment); - - this.regexp = new RegExp(compiled, config.caseInsensitive ? 'i' : undefined); - this.prefix = segments[0]; - this.$$paramNames = paramNames; -} - -/** - * @ngdoc function - * @name ui.router.util.type:UrlMatcher#concat - * @methodOf ui.router.util.type:UrlMatcher - * - * @description - * Returns a new matcher for a pattern constructed by appending the path part and adding the - * search parameters of the specified pattern to this pattern. The current pattern is not - * modified. This can be understood as creating a pattern for URLs that are relative to (or - * suffixes of) the current pattern. - * - * @example - * The following two matchers are equivalent: - *
- * new UrlMatcher('/user/{id}?q').concat('/details?date');
- * new UrlMatcher('/user/{id}/details?q&date');
- * 
- * - * @param {string} pattern The pattern to append. - * @param {Object} config An object hash of the configuration for the matcher. - * @returns {UrlMatcher} A matcher for the concatenated pattern. - */ -UrlMatcher.prototype.concat = function (pattern, config) { - // Because order of search parameters is irrelevant, we can add our own search - // parameters to the end of the new pattern. Parse the new pattern by itself - // and then join the bits together, but it's much easier to do this on a string level. - var defaultConfig = { - caseInsensitive: $$UMFP.caseInsensitive(), - strict: $$UMFP.strictMode(), - squash: $$UMFP.defaultSquashPolicy() - }; - return new UrlMatcher(this.sourcePath + pattern + this.sourceSearch, extend(defaultConfig, config), this); -}; - -UrlMatcher.prototype.toString = function () { - return this.source; -}; - -/** - * @ngdoc function - * @name ui.router.util.type:UrlMatcher#exec - * @methodOf ui.router.util.type:UrlMatcher - * - * @description - * Tests the specified path against this matcher, and returns an object containing the captured - * parameter values, or null if the path does not match. The returned object contains the values - * of any search parameters that are mentioned in the pattern, but their value may be null if - * they are not present in `searchParams`. This means that search parameters are always treated - * as optional. - * - * @example - *
- * new UrlMatcher('/user/{id}?q&r').exec('/user/bob', {
- *   x: '1', q: 'hello'
- * });
- * // returns { id: 'bob', q: 'hello', r: null }
- * 
- * - * @param {string} path The URL path to match, e.g. `$location.path()`. - * @param {Object} searchParams URL search parameters, e.g. `$location.search()`. - * @returns {Object} The captured parameter values. - */ -UrlMatcher.prototype.exec = function (path, searchParams) { - var m = this.regexp.exec(path); - if (!m) return null; - searchParams = searchParams || {}; - - var paramNames = this.parameters(), nTotal = paramNames.length, - nPath = this.segments.length - 1, - values = {}, i, j, cfg, paramName; - - if (nPath !== m.length - 1) throw new Error("Unbalanced capture group in route '" + this.source + "'"); - - function decodePathArray(string) { - function reverseString(str) { return str.split("").reverse().join(""); } - function unquoteDashes(str) { return str.replace(/\\-/, "-"); } - - var split = reverseString(string).split(/-(?!\\)/); - var allReversed = map(split, reverseString); - return map(allReversed, unquoteDashes).reverse(); - } - - for (i = 0; i < nPath; i++) { - paramName = paramNames[i]; - var param = this.params[paramName]; - var paramVal = m[i+1]; - // if the param value matches a pre-replace pair, replace the value before decoding. - for (j = 0; j < param.replace; j++) { - if (param.replace[j].from === paramVal) paramVal = param.replace[j].to; - } - if (paramVal && param.array === true) paramVal = decodePathArray(paramVal); - values[paramName] = param.value(paramVal); - } - for (/**/; i < nTotal; i++) { - paramName = paramNames[i]; - values[paramName] = this.params[paramName].value(searchParams[paramName]); - } - - return values; -}; - -/** - * @ngdoc function - * @name ui.router.util.type:UrlMatcher#parameters - * @methodOf ui.router.util.type:UrlMatcher - * - * @description - * Returns the names of all path and search parameters of this pattern in an unspecified order. - * - * @returns {Array.} An array of parameter names. Must be treated as read-only. If the - * pattern has no parameters, an empty array is returned. - */ -UrlMatcher.prototype.parameters = function (param) { - if (!isDefined(param)) return this.$$paramNames; - return this.params[param] || null; -}; - -/** - * @ngdoc function - * @name ui.router.util.type:UrlMatcher#validate - * @methodOf ui.router.util.type:UrlMatcher - * - * @description - * Checks an object hash of parameters to validate their correctness according to the parameter - * types of this `UrlMatcher`. - * - * @param {Object} params The object hash of parameters to validate. - * @returns {boolean} Returns `true` if `params` validates, otherwise `false`. - */ -UrlMatcher.prototype.validates = function (params) { - return this.params.$$validates(params); -}; - -/** - * @ngdoc function - * @name ui.router.util.type:UrlMatcher#format - * @methodOf ui.router.util.type:UrlMatcher - * - * @description - * Creates a URL that matches this pattern by substituting the specified values - * for the path and search parameters. Null values for path parameters are - * treated as empty strings. - * - * @example - *
- * new UrlMatcher('/user/{id}?q').format({ id:'bob', q:'yes' });
- * // returns '/user/bob?q=yes'
- * 
- * - * @param {Object} values the values to substitute for the parameters in this pattern. - * @returns {string} the formatted URL (path and optionally search part). - */ -UrlMatcher.prototype.format = function (values) { - values = values || {}; - var segments = this.segments, params = this.parameters(), paramset = this.params; - if (!this.validates(values)) return null; - - var i, search = false, nPath = segments.length - 1, nTotal = params.length, result = segments[0]; - - function encodeDashes(str) { // Replace dashes with encoded "\-" - return encodeURIComponent(str).replace(/-/g, function(c) { return '%5C%' + c.charCodeAt(0).toString(16).toUpperCase(); }); - } - - for (i = 0; i < nTotal; i++) { - var isPathParam = i < nPath; - var name = params[i], param = paramset[name], value = param.value(values[name]); - var isDefaultValue = param.isOptional && param.type.equals(param.value(), value); - var squash = isDefaultValue ? param.squash : false; - var encoded = param.type.encode(value); - - if (isPathParam) { - var nextSegment = segments[i + 1]; - if (squash === false) { - if (encoded != null) { - if (isArray(encoded)) { - result += map(encoded, encodeDashes).join("-"); - } else { - result += encodeURIComponent(encoded); - } - } - result += nextSegment; - } else if (squash === true) { - var capture = result.match(/\/$/) ? /\/?(.*)/ : /(.*)/; - result += nextSegment.match(capture)[1]; - } else if (isString(squash)) { - result += squash + nextSegment; - } - } else { - if (encoded == null || (isDefaultValue && squash !== false)) continue; - if (!isArray(encoded)) encoded = [ encoded ]; - encoded = map(encoded, encodeURIComponent).join('&' + name + '='); - result += (search ? '&' : '?') + (name + '=' + encoded); - search = true; - } - } - - return result; -}; - -/** - * @ngdoc object - * @name ui.router.util.type:Type - * - * @description - * Implements an interface to define custom parameter types that can be decoded from and encoded to - * string parameters matched in a URL. Used by {@link ui.router.util.type:UrlMatcher `UrlMatcher`} - * objects when matching or formatting URLs, or comparing or validating parameter values. - * - * See {@link ui.router.util.$urlMatcherFactory#methods_type `$urlMatcherFactory#type()`} for more - * information on registering custom types. - * - * @param {Object} config A configuration object which contains the custom type definition. The object's - * properties will override the default methods and/or pattern in `Type`'s public interface. - * @example - *
- * {
- *   decode: function(val) { return parseInt(val, 10); },
- *   encode: function(val) { return val && val.toString(); },
- *   equals: function(a, b) { return this.is(a) && a === b; },
- *   is: function(val) { return angular.isNumber(val) isFinite(val) && val % 1 === 0; },
- *   pattern: /\d+/
- * }
- * 
- * - * @property {RegExp} pattern The regular expression pattern used to match values of this type when - * coming from a substring of a URL. - * - * @returns {Object} Returns a new `Type` object. - */ -function Type(config) { - extend(this, config); -} - -/** - * @ngdoc function - * @name ui.router.util.type:Type#is - * @methodOf ui.router.util.type:Type - * - * @description - * Detects whether a value is of a particular type. Accepts a native (decoded) value - * and determines whether it matches the current `Type` object. - * - * @param {*} val The value to check. - * @param {string} key Optional. If the type check is happening in the context of a specific - * {@link ui.router.util.type:UrlMatcher `UrlMatcher`} object, this is the name of the - * parameter in which `val` is stored. Can be used for meta-programming of `Type` objects. - * @returns {Boolean} Returns `true` if the value matches the type, otherwise `false`. - */ -Type.prototype.is = function(val, key) { - return true; -}; - -/** - * @ngdoc function - * @name ui.router.util.type:Type#encode - * @methodOf ui.router.util.type:Type - * - * @description - * Encodes a custom/native type value to a string that can be embedded in a URL. Note that the - * return value does *not* need to be URL-safe (i.e. passed through `encodeURIComponent()`), it - * only needs to be a representation of `val` that has been coerced to a string. - * - * @param {*} val The value to encode. - * @param {string} key The name of the parameter in which `val` is stored. Can be used for - * meta-programming of `Type` objects. - * @returns {string} Returns a string representation of `val` that can be encoded in a URL. - */ -Type.prototype.encode = function(val, key) { - return val; -}; - -/** - * @ngdoc function - * @name ui.router.util.type:Type#decode - * @methodOf ui.router.util.type:Type - * - * @description - * Converts a parameter value (from URL string or transition param) to a custom/native value. - * - * @param {string} val The URL parameter value to decode. - * @param {string} key The name of the parameter in which `val` is stored. Can be used for - * meta-programming of `Type` objects. - * @returns {*} Returns a custom representation of the URL parameter value. - */ -Type.prototype.decode = function(val, key) { - return val; -}; - -/** - * @ngdoc function - * @name ui.router.util.type:Type#equals - * @methodOf ui.router.util.type:Type - * - * @description - * Determines whether two decoded values are equivalent. - * - * @param {*} a A value to compare against. - * @param {*} b A value to compare against. - * @returns {Boolean} Returns `true` if the values are equivalent/equal, otherwise `false`. - */ -Type.prototype.equals = function(a, b) { - return a == b; -}; - -Type.prototype.$subPattern = function() { - var sub = this.pattern.toString(); - return sub.substr(1, sub.length - 2); -}; - -Type.prototype.pattern = /.*/; - -Type.prototype.toString = function() { return "{Type:" + this.name + "}"; }; - -/* - * Wraps an existing custom Type as an array of Type, depending on 'mode'. - * e.g.: - * - urlmatcher pattern "/path?{queryParam[]:int}" - * - url: "/path?queryParam=1&queryParam=2 - * - $stateParams.queryParam will be [1, 2] - * if `mode` is "auto", then - * - url: "/path?queryParam=1 will create $stateParams.queryParam: 1 - * - url: "/path?queryParam=1&queryParam=2 will create $stateParams.queryParam: [1, 2] - */ -Type.prototype.$asArray = function(mode, isSearch) { - if (!mode) return this; - if (mode === "auto" && !isSearch) throw new Error("'auto' array mode is for query parameters only"); - return new ArrayType(this, mode); - - function ArrayType(type, mode) { - function bindTo(type, callbackName) { - return function() { - return type[callbackName].apply(type, arguments); - }; - } - - // Wrap non-array value as array - function arrayWrap(val) { return isArray(val) ? val : (isDefined(val) ? [ val ] : []); } - // Unwrap array value for "auto" mode. Return undefined for empty array. - function arrayUnwrap(val) { - switch(val.length) { - case 0: return undefined; - case 1: return mode === "auto" ? val[0] : val; - default: return val; - } - } - function falsey(val) { return !val; } - - // Wraps type (.is/.encode/.decode) functions to operate on each value of an array - function arrayHandler(callback, allTruthyMode) { - return function handleArray(val) { - val = arrayWrap(val); - var result = map(val, callback); - if (allTruthyMode === true) - return filter(result, falsey).length === 0; - return arrayUnwrap(result); - }; - } - - // Wraps type (.equals) functions to operate on each value of an array - function arrayEqualsHandler(callback) { - return function handleArray(val1, val2) { - var left = arrayWrap(val1), right = arrayWrap(val2); - if (left.length !== right.length) return false; - for (var i = 0; i < left.length; i++) { - if (!callback(left[i], right[i])) return false; - } - return true; - }; - } - - this.encode = arrayHandler(bindTo(type, 'encode')); - this.decode = arrayHandler(bindTo(type, 'decode')); - this.is = arrayHandler(bindTo(type, 'is'), true); - this.equals = arrayEqualsHandler(bindTo(type, 'equals')); - this.pattern = type.pattern; - this.$arrayMode = mode; - } -}; - - - -/** - * @ngdoc object - * @name ui.router.util.$urlMatcherFactory - * - * @description - * Factory for {@link ui.router.util.type:UrlMatcher `UrlMatcher`} instances. The factory - * is also available to providers under the name `$urlMatcherFactoryProvider`. - */ -function $UrlMatcherFactory() { - $$UMFP = this; - - var isCaseInsensitive = false, isStrictMode = true, defaultSquashPolicy = false; - - function valToString(val) { return val != null ? val.toString().replace(/\//g, "%2F") : val; } - function valFromString(val) { return val != null ? val.toString().replace(/%2F/g, "/") : val; } -// TODO: in 1.0, make string .is() return false if value is undefined by default. -// function regexpMatches(val) { /*jshint validthis:true */ return isDefined(val) && this.pattern.test(val); } - function regexpMatches(val) { /*jshint validthis:true */ return this.pattern.test(val); } - - var $types = {}, enqueue = true, typeQueue = [], injector, defaultTypes = { - string: { - encode: valToString, - decode: valFromString, - is: regexpMatches, - pattern: /[^/]*/ - }, - int: { - encode: valToString, - decode: function(val) { return parseInt(val, 10); }, - is: function(val) { return isDefined(val) && this.decode(val.toString()) === val; }, - pattern: /\d+/ - }, - bool: { - encode: function(val) { return val ? 1 : 0; }, - decode: function(val) { return parseInt(val, 10) !== 0; }, - is: function(val) { return val === true || val === false; }, - pattern: /0|1/ - }, - date: { - encode: function (val) { - if (!this.is(val)) - return undefined; - return [ val.getFullYear(), - ('0' + (val.getMonth() + 1)).slice(-2), - ('0' + val.getDate()).slice(-2) - ].join("-"); - }, - decode: function (val) { - if (this.is(val)) return val; - var match = this.capture.exec(val); - return match ? new Date(match[1], match[2] - 1, match[3]) : undefined; - }, - is: function(val) { return val instanceof Date && !isNaN(val.valueOf()); }, - equals: function (a, b) { return this.is(a) && this.is(b) && a.toISOString() === b.toISOString(); }, - pattern: /[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/, - capture: /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/ - }, - json: { - encode: angular.toJson, - decode: angular.fromJson, - is: angular.isObject, - equals: angular.equals, - pattern: /[^/]*/ - }, - any: { // does not encode/decode - encode: angular.identity, - decode: angular.identity, - is: angular.identity, - equals: angular.equals, - pattern: /.*/ - } - }; - - function getDefaultConfig() { - return { - strict: isStrictMode, - caseInsensitive: isCaseInsensitive - }; - } - - function isInjectable(value) { - return (isFunction(value) || (isArray(value) && isFunction(value[value.length - 1]))); - } - - /** - * [Internal] Get the default value of a parameter, which may be an injectable function. - */ - $UrlMatcherFactory.$$getDefaultValue = function(config) { - if (!isInjectable(config.value)) return config.value; - if (!injector) throw new Error("Injectable functions cannot be called at configuration time"); - return injector.invoke(config.value); - }; - - /** - * @ngdoc function - * @name ui.router.util.$urlMatcherFactory#caseInsensitive - * @methodOf ui.router.util.$urlMatcherFactory - * - * @description - * Defines whether URL matching should be case sensitive (the default behavior), or not. - * - * @param {boolean} value `false` to match URL in a case sensitive manner; otherwise `true`; - * @returns {boolean} the current value of caseInsensitive - */ - this.caseInsensitive = function(value) { - if (isDefined(value)) - isCaseInsensitive = value; - return isCaseInsensitive; - }; - - /** - * @ngdoc function - * @name ui.router.util.$urlMatcherFactory#strictMode - * @methodOf ui.router.util.$urlMatcherFactory - * - * @description - * Defines whether URLs should match trailing slashes, or not (the default behavior). - * - * @param {boolean=} value `false` to match trailing slashes in URLs, otherwise `true`. - * @returns {boolean} the current value of strictMode - */ - this.strictMode = function(value) { - if (isDefined(value)) - isStrictMode = value; - return isStrictMode; - }; - - /** - * @ngdoc function - * @name ui.router.util.$urlMatcherFactory#defaultSquashPolicy - * @methodOf ui.router.util.$urlMatcherFactory - * - * @description - * Sets the default behavior when generating or matching URLs with default parameter values. - * - * @param {string} value A string that defines the default parameter URL squashing behavior. - * `nosquash`: When generating an href with a default parameter value, do not squash the parameter value from the URL - * `slash`: When generating an href with a default parameter value, squash (remove) the parameter value, and, if the - * parameter is surrounded by slashes, squash (remove) one slash from the URL - * any other string, e.g. "~": When generating an href with a default parameter value, squash (remove) - * the parameter value from the URL and replace it with this string. - */ - this.defaultSquashPolicy = function(value) { - if (!isDefined(value)) return defaultSquashPolicy; - if (value !== true && value !== false && !isString(value)) - throw new Error("Invalid squash policy: " + value + ". Valid policies: false, true, arbitrary-string"); - defaultSquashPolicy = value; - return value; - }; - - /** - * @ngdoc function - * @name ui.router.util.$urlMatcherFactory#compile - * @methodOf ui.router.util.$urlMatcherFactory - * - * @description - * Creates a {@link ui.router.util.type:UrlMatcher `UrlMatcher`} for the specified pattern. - * - * @param {string} pattern The URL pattern. - * @param {Object} config The config object hash. - * @returns {UrlMatcher} The UrlMatcher. - */ - this.compile = function (pattern, config) { - return new UrlMatcher(pattern, extend(getDefaultConfig(), config)); - }; - - /** - * @ngdoc function - * @name ui.router.util.$urlMatcherFactory#isMatcher - * @methodOf ui.router.util.$urlMatcherFactory - * - * @description - * Returns true if the specified object is a `UrlMatcher`, or false otherwise. - * - * @param {Object} object The object to perform the type check against. - * @returns {Boolean} Returns `true` if the object matches the `UrlMatcher` interface, by - * implementing all the same methods. - */ - this.isMatcher = function (o) { - if (!isObject(o)) return false; - var result = true; - - forEach(UrlMatcher.prototype, function(val, name) { - if (isFunction(val)) { - result = result && (isDefined(o[name]) && isFunction(o[name])); - } - }); - return result; - }; - - /** - * @ngdoc function - * @name ui.router.util.$urlMatcherFactory#type - * @methodOf ui.router.util.$urlMatcherFactory - * - * @description - * Registers a custom {@link ui.router.util.type:Type `Type`} object that can be used to - * generate URLs with typed parameters. - * - * @param {string} name The type name. - * @param {Object|Function} definition The type definition. See - * {@link ui.router.util.type:Type `Type`} for information on the values accepted. - * @param {Object|Function} definitionFn (optional) A function that is injected before the app - * runtime starts. The result of this function is merged into the existing `definition`. - * See {@link ui.router.util.type:Type `Type`} for information on the values accepted. - * - * @returns {Object} Returns `$urlMatcherFactoryProvider`. - * - * @example - * This is a simple example of a custom type that encodes and decodes items from an - * array, using the array index as the URL-encoded value: - * - *
-   * var list = ['John', 'Paul', 'George', 'Ringo'];
-   *
-   * $urlMatcherFactoryProvider.type('listItem', {
-   *   encode: function(item) {
-   *     // Represent the list item in the URL using its corresponding index
-   *     return list.indexOf(item);
-   *   },
-   *   decode: function(item) {
-   *     // Look up the list item by index
-   *     return list[parseInt(item, 10)];
-   *   },
-   *   is: function(item) {
-   *     // Ensure the item is valid by checking to see that it appears
-   *     // in the list
-   *     return list.indexOf(item) > -1;
-   *   }
-   * });
-   *
-   * $stateProvider.state('list', {
-   *   url: "/list/{item:listItem}",
-   *   controller: function($scope, $stateParams) {
-   *     console.log($stateParams.item);
-   *   }
-   * });
-   *
-   * // ...
-   *
-   * // Changes URL to '/list/3', logs "Ringo" to the console
-   * $state.go('list', { item: "Ringo" });
-   * 
- * - * This is a more complex example of a type that relies on dependency injection to - * interact with services, and uses the parameter name from the URL to infer how to - * handle encoding and decoding parameter values: - * - *
-   * // Defines a custom type that gets a value from a service,
-   * // where each service gets different types of values from
-   * // a backend API:
-   * $urlMatcherFactoryProvider.type('dbObject', {}, function(Users, Posts) {
-   *
-   *   // Matches up services to URL parameter names
-   *   var services = {
-   *     user: Users,
-   *     post: Posts
-   *   };
-   *
-   *   return {
-   *     encode: function(object) {
-   *       // Represent the object in the URL using its unique ID
-   *       return object.id;
-   *     },
-   *     decode: function(value, key) {
-   *       // Look up the object by ID, using the parameter
-   *       // name (key) to call the correct service
-   *       return services[key].findById(value);
-   *     },
-   *     is: function(object, key) {
-   *       // Check that object is a valid dbObject
-   *       return angular.isObject(object) && object.id && services[key];
-   *     }
-   *     equals: function(a, b) {
-   *       // Check the equality of decoded objects by comparing
-   *       // their unique IDs
-   *       return a.id === b.id;
-   *     }
-   *   };
-   * });
-   *
-   * // In a config() block, you can then attach URLs with
-   * // type-annotated parameters:
-   * $stateProvider.state('users', {
-   *   url: "/users",
-   *   // ...
-   * }).state('users.item', {
-   *   url: "/{user:dbObject}",
-   *   controller: function($scope, $stateParams) {
-   *     // $stateParams.user will now be an object returned from
-   *     // the Users service
-   *   },
-   *   // ...
-   * });
-   * 
- */ - this.type = function (name, definition, definitionFn) { - if (!isDefined(definition)) return $types[name]; - if ($types.hasOwnProperty(name)) throw new Error("A type named '" + name + "' has already been defined."); - - $types[name] = new Type(extend({ name: name }, definition)); - if (definitionFn) { - typeQueue.push({ name: name, def: definitionFn }); - if (!enqueue) flushTypeQueue(); - } - return this; - }; - - // `flushTypeQueue()` waits until `$urlMatcherFactory` is injected before invoking the queued `definitionFn`s - function flushTypeQueue() { - while(typeQueue.length) { - var type = typeQueue.shift(); - if (type.pattern) throw new Error("You cannot override a type's .pattern at runtime."); - angular.extend($types[type.name], injector.invoke(type.def)); - } - } - - // Register default types. Store them in the prototype of $types. - forEach(defaultTypes, function(type, name) { $types[name] = new Type(extend({name: name}, type)); }); - $types = inherit($types, {}); - - /* No need to document $get, since it returns this */ - this.$get = ['$injector', function ($injector) { - injector = $injector; - enqueue = false; - flushTypeQueue(); - - forEach(defaultTypes, function(type, name) { - if (!$types[name]) $types[name] = new Type(type); - }); - return this; - }]; - - this.Param = function Param(id, type, config, location) { - var self = this; - config = unwrapShorthand(config); - type = getType(config, type, location); - var arrayMode = getArrayMode(); - type = arrayMode ? type.$asArray(arrayMode, location === "search") : type; - if (type.name === "string" && !arrayMode && location === "path" && config.value === undefined) - config.value = ""; // for 0.2.x; in 0.3.0+ do not automatically default to "" - var isOptional = config.value !== undefined; - var squash = getSquashPolicy(config, isOptional); - var replace = getReplace(config, arrayMode, isOptional, squash); - - function unwrapShorthand(config) { - var keys = isObject(config) ? objectKeys(config) : []; - var isShorthand = indexOf(keys, "value") === -1 && indexOf(keys, "type") === -1 && - indexOf(keys, "squash") === -1 && indexOf(keys, "array") === -1; - if (isShorthand) config = { value: config }; - config.$$fn = isInjectable(config.value) ? config.value : function () { return config.value; }; - return config; - } - - function getType(config, urlType, location) { - if (config.type && urlType) throw new Error("Param '"+id+"' has two type configurations."); - if (urlType) return urlType; - if (!config.type) return (location === "config" ? $types.any : $types.string); - return config.type instanceof Type ? config.type : new Type(config.type); - } - - // array config: param name (param[]) overrides default settings. explicit config overrides param name. - function getArrayMode() { - var arrayDefaults = { array: (location === "search" ? "auto" : false) }; - var arrayParamNomenclature = id.match(/\[\]$/) ? { array: true } : {}; - return extend(arrayDefaults, arrayParamNomenclature, config).array; - } - - /** - * returns false, true, or the squash value to indicate the "default parameter url squash policy". - */ - function getSquashPolicy(config, isOptional) { - var squash = config.squash; - if (!isOptional || squash === false) return false; - if (!isDefined(squash) || squash == null) return defaultSquashPolicy; - if (squash === true || isString(squash)) return squash; - throw new Error("Invalid squash policy: '" + squash + "'. Valid policies: false, true, or arbitrary string"); - } - - function getReplace(config, arrayMode, isOptional, squash) { - var replace, configuredKeys, defaultPolicy = [ - { from: "", to: (isOptional || arrayMode ? undefined : "") }, - { from: null, to: (isOptional || arrayMode ? undefined : "") } - ]; - replace = isArray(config.replace) ? config.replace : []; - if (isString(squash)) - replace.push({ from: squash, to: undefined }); - configuredKeys = map(replace, function(item) { return item.from; } ); - return filter(defaultPolicy, function(item) { return indexOf(configuredKeys, item.from) === -1; }).concat(replace); - } - - /** - * [Internal] Get the default value of a parameter, which may be an injectable function. - */ - function $$getDefaultValue() { - if (!injector) throw new Error("Injectable functions cannot be called at configuration time"); - return injector.invoke(config.$$fn); - } - - /** - * [Internal] Gets the decoded representation of a value if the value is defined, otherwise, returns the - * default value, which may be the result of an injectable function. - */ - function $value(value) { - function hasReplaceVal(val) { return function(obj) { return obj.from === val; }; } - function $replace(value) { - var replacement = map(filter(self.replace, hasReplaceVal(value)), function(obj) { return obj.to; }); - return replacement.length ? replacement[0] : value; - } - value = $replace(value); - return isDefined(value) ? self.type.decode(value) : $$getDefaultValue(); - } - - function toString() { return "{Param:" + id + " " + type + " squash: '" + squash + "' optional: " + isOptional + "}"; } - - extend(this, { - id: id, - type: type, - location: location, - array: arrayMode, - squash: squash, - replace: replace, - isOptional: isOptional, - value: $value, - dynamic: undefined, - config: config, - toString: toString - }); - }; - - function ParamSet(params) { - extend(this, params || {}); - } - - ParamSet.prototype = { - $$new: function() { - return inherit(this, extend(new ParamSet(), { $$parent: this})); - }, - $$keys: function () { - var keys = [], chain = [], parent = this, - ignore = objectKeys(ParamSet.prototype); - while (parent) { chain.push(parent); parent = parent.$$parent; } - chain.reverse(); - forEach(chain, function(paramset) { - forEach(objectKeys(paramset), function(key) { - if (indexOf(keys, key) === -1 && indexOf(ignore, key) === -1) keys.push(key); - }); - }); - return keys; - }, - $$values: function(paramValues) { - var values = {}, self = this; - forEach(self.$$keys(), function(key) { - values[key] = self[key].value(paramValues && paramValues[key]); - }); - return values; - }, - $$equals: function(paramValues1, paramValues2) { - var equal = true, self = this; - forEach(self.$$keys(), function(key) { - var left = paramValues1 && paramValues1[key], right = paramValues2 && paramValues2[key]; - if (!self[key].type.equals(left, right)) equal = false; - }); - return equal; - }, - $$validates: function $$validate(paramValues) { - var result = true, isOptional, val, param, self = this; - - forEach(this.$$keys(), function(key) { - param = self[key]; - val = paramValues[key]; - isOptional = !val && param.isOptional; - result = result && (isOptional || !!param.type.is(val)); - }); - return result; - }, - $$parent: undefined - }; - - this.ParamSet = ParamSet; -} - -// Register as a provider so it's available to other providers -angular.module('ui.router.util').provider('$urlMatcherFactory', $UrlMatcherFactory); -angular.module('ui.router.util').run(['$urlMatcherFactory', function($urlMatcherFactory) { }]); - -/** - * @ngdoc object - * @name ui.router.router.$urlRouterProvider - * - * @requires ui.router.util.$urlMatcherFactoryProvider - * @requires $locationProvider - * - * @description - * `$urlRouterProvider` has the responsibility of watching `$location`. - * When `$location` changes it runs through a list of rules one by one until a - * match is found. `$urlRouterProvider` is used behind the scenes anytime you specify - * a url in a state configuration. All urls are compiled into a UrlMatcher object. - * - * There are several methods on `$urlRouterProvider` that make it useful to use directly - * in your module config. - */ -$UrlRouterProvider.$inject = ['$locationProvider', '$urlMatcherFactoryProvider']; -function $UrlRouterProvider( $locationProvider, $urlMatcherFactory) { - var rules = [], otherwise = null, interceptDeferred = false, listener; - - // Returns a string that is a prefix of all strings matching the RegExp - function regExpPrefix(re) { - var prefix = /^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(re.source); - return (prefix != null) ? prefix[1].replace(/\\(.)/g, "$1") : ''; - } - - // Interpolates matched values into a String.replace()-style pattern - function interpolate(pattern, match) { - return pattern.replace(/\$(\$|\d{1,2})/, function (m, what) { - return match[what === '$' ? 0 : Number(what)]; - }); - } - - /** - * @ngdoc function - * @name ui.router.router.$urlRouterProvider#rule - * @methodOf ui.router.router.$urlRouterProvider - * - * @description - * Defines rules that are used by `$urlRouterProvider` to find matches for - * specific URLs. - * - * @example - *
-   * var app = angular.module('app', ['ui.router.router']);
-   *
-   * app.config(function ($urlRouterProvider) {
-   *   // Here's an example of how you might allow case insensitive urls
-   *   $urlRouterProvider.rule(function ($injector, $location) {
-   *     var path = $location.path(),
-   *         normalized = path.toLowerCase();
-   *
-   *     if (path !== normalized) {
-   *       return normalized;
-   *     }
-   *   });
-   * });
-   * 
- * - * @param {object} rule Handler function that takes `$injector` and `$location` - * services as arguments. You can use them to return a valid path as a string. - * - * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance - */ - this.rule = function (rule) { - if (!isFunction(rule)) throw new Error("'rule' must be a function"); - rules.push(rule); - return this; - }; - - /** - * @ngdoc object - * @name ui.router.router.$urlRouterProvider#otherwise - * @methodOf ui.router.router.$urlRouterProvider - * - * @description - * Defines a path that is used when an invalid route is requested. - * - * @example - *
-   * var app = angular.module('app', ['ui.router.router']);
-   *
-   * app.config(function ($urlRouterProvider) {
-   *   // if the path doesn't match any of the urls you configured
-   *   // otherwise will take care of routing the user to the
-   *   // specified url
-   *   $urlRouterProvider.otherwise('/index');
-   *
-   *   // Example of using function rule as param
-   *   $urlRouterProvider.otherwise(function ($injector, $location) {
-   *     return '/a/valid/url';
-   *   });
-   * });
-   * 
- * - * @param {string|object} rule The url path you want to redirect to or a function - * rule that returns the url path. The function version is passed two params: - * `$injector` and `$location` services, and must return a url string. - * - * @return {object} `$urlRouterProvider` - `$urlRouterProvider` instance - */ - this.otherwise = function (rule) { - if (isString(rule)) { - var redirect = rule; - rule = function () { return redirect; }; - } - else if (!isFunction(rule)) throw new Error("'rule' must be a function"); - otherwise = rule; - return this; - }; - - - function handleIfMatch($injector, handler, match) { - if (!match) return false; - var result = $injector.invoke(handler, handler, { $match: match }); - return isDefined(result) ? result : true; - } - - /** - * @ngdoc function - * @name ui.router.router.$urlRouterProvider#when - * @methodOf ui.router.router.$urlRouterProvider - * - * @description - * Registers a handler for a given url matching. if handle is a string, it is - * treated as a redirect, and is interpolated according to the syntax of match - * (i.e. like `String.replace()` for `RegExp`, or like a `UrlMatcher` pattern otherwise). - * - * If the handler is a function, it is injectable. It gets invoked if `$location` - * matches. You have the option of inject the match object as `$match`. - * - * The handler can return - * - * - **falsy** to indicate that the rule didn't match after all, then `$urlRouter` - * will continue trying to find another one that matches. - * - **string** which is treated as a redirect and passed to `$location.url()` - * - **void** or any **truthy** value tells `$urlRouter` that the url was handled. - * - * @example - *
-   * var app = angular.module('app', ['ui.router.router']);
-   *
-   * app.config(function ($urlRouterProvider) {
-   *   $urlRouterProvider.when($state.url, function ($match, $stateParams) {
-   *     if ($state.$current.navigable !== state ||
-   *         !equalForKeys($match, $stateParams) {
-   *      $state.transitionTo(state, $match, false);
-   *     }
-   *   });
-   * });
-   * 
- * - * @param {string|object} what The incoming path that you want to redirect. - * @param {string|object} handler The path you want to redirect your user to. - */ - this.when = function (what, handler) { - var redirect, handlerIsString = isString(handler); - if (isString(what)) what = $urlMatcherFactory.compile(what); - - if (!handlerIsString && !isFunction(handler) && !isArray(handler)) - throw new Error("invalid 'handler' in when()"); - - var strategies = { - matcher: function (what, handler) { - if (handlerIsString) { - redirect = $urlMatcherFactory.compile(handler); - handler = ['$match', function ($match) { return redirect.format($match); }]; - } - return extend(function ($injector, $location) { - return handleIfMatch($injector, handler, what.exec($location.path(), $location.search())); - }, { - prefix: isString(what.prefix) ? what.prefix : '' - }); - }, - regex: function (what, handler) { - if (what.global || what.sticky) throw new Error("when() RegExp must not be global or sticky"); - - if (handlerIsString) { - redirect = handler; - handler = ['$match', function ($match) { return interpolate(redirect, $match); }]; - } - return extend(function ($injector, $location) { - return handleIfMatch($injector, handler, what.exec($location.path())); - }, { - prefix: regExpPrefix(what) - }); - } - }; - - var check = { matcher: $urlMatcherFactory.isMatcher(what), regex: what instanceof RegExp }; - - for (var n in check) { - if (check[n]) return this.rule(strategies[n](what, handler)); - } - - throw new Error("invalid 'what' in when()"); - }; - - /** - * @ngdoc function - * @name ui.router.router.$urlRouterProvider#deferIntercept - * @methodOf ui.router.router.$urlRouterProvider - * - * @description - * Disables (or enables) deferring location change interception. - * - * If you wish to customize the behavior of syncing the URL (for example, if you wish to - * defer a transition but maintain the current URL), call this method at configuration time. - * Then, at run time, call `$urlRouter.listen()` after you have configured your own - * `$locationChangeSuccess` event handler. - * - * @example - *
-   * var app = angular.module('app', ['ui.router.router']);
-   *
-   * app.config(function ($urlRouterProvider) {
-   *
-   *   // Prevent $urlRouter from automatically intercepting URL changes;
-   *   // this allows you to configure custom behavior in between
-   *   // location changes and route synchronization:
-   *   $urlRouterProvider.deferIntercept();
-   *
-   * }).run(function ($rootScope, $urlRouter, UserService) {
-   *
-   *   $rootScope.$on('$locationChangeSuccess', function(e) {
-   *     // UserService is an example service for managing user state
-   *     if (UserService.isLoggedIn()) return;
-   *
-   *     // Prevent $urlRouter's default handler from firing
-   *     e.preventDefault();
-   *
-   *     UserService.handleLogin().then(function() {
-   *       // Once the user has logged in, sync the current URL
-   *       // to the router:
-   *       $urlRouter.sync();
-   *     });
-   *   });
-   *
-   *   // Configures $urlRouter's listener *after* your custom listener
-   *   $urlRouter.listen();
-   * });
-   * 
- * - * @param {boolean} defer Indicates whether to defer location change interception. Passing - no parameter is equivalent to `true`. - */ - this.deferIntercept = function (defer) { - if (defer === undefined) defer = true; - interceptDeferred = defer; - }; - - /** - * @ngdoc object - * @name ui.router.router.$urlRouter - * - * @requires $location - * @requires $rootScope - * @requires $injector - * @requires $browser - * - * @description - * - */ - this.$get = $get; - $get.$inject = ['$location', '$rootScope', '$injector', '$browser']; - function $get( $location, $rootScope, $injector, $browser) { - - var baseHref = $browser.baseHref(), location = $location.url(), lastPushedUrl; - - function appendBasePath(url, isHtml5, absolute) { - if (baseHref === '/') return url; - if (isHtml5) return baseHref.slice(0, -1) + url; - if (absolute) return baseHref.slice(1) + url; - return url; - } - - // TODO: Optimize groups of rules with non-empty prefix into some sort of decision tree - function update(evt) { - if (evt && evt.defaultPrevented) return; - var ignoreUpdate = lastPushedUrl && $location.url() === lastPushedUrl; - lastPushedUrl = undefined; - if (ignoreUpdate) return true; - - function check(rule) { - var handled = rule($injector, $location); - - if (!handled) return false; - if (isString(handled)) $location.replace().url(handled); - return true; - } - var n = rules.length, i; - - for (i = 0; i < n; i++) { - if (check(rules[i])) return; - } - // always check otherwise last to allow dynamic updates to the set of rules - if (otherwise) check(otherwise); - } - - function listen() { - listener = listener || $rootScope.$on('$locationChangeSuccess', update); - return listener; - } - - if (!interceptDeferred) listen(); - - return { - /** - * @ngdoc function - * @name ui.router.router.$urlRouter#sync - * @methodOf ui.router.router.$urlRouter - * - * @description - * Triggers an update; the same update that happens when the address bar url changes, aka `$locationChangeSuccess`. - * This method is useful when you need to use `preventDefault()` on the `$locationChangeSuccess` event, - * perform some custom logic (route protection, auth, config, redirection, etc) and then finally proceed - * with the transition by calling `$urlRouter.sync()`. - * - * @example - *
-       * angular.module('app', ['ui.router'])
-       *   .run(function($rootScope, $urlRouter) {
-       *     $rootScope.$on('$locationChangeSuccess', function(evt) {
-       *       // Halt state change from even starting
-       *       evt.preventDefault();
-       *       // Perform custom logic
-       *       var meetsRequirement = ...
-       *       // Continue with the update and state transition if logic allows
-       *       if (meetsRequirement) $urlRouter.sync();
-       *     });
-       * });
-       * 
- */ - sync: function() { - update(); - }, - - listen: function() { - return listen(); - }, - - update: function(read) { - if (read) { - location = $location.url(); - return; - } - if ($location.url() === location) return; - - $location.url(location); - $location.replace(); - }, - - push: function(urlMatcher, params, options) { - $location.url(urlMatcher.format(params || {})); - lastPushedUrl = options && options.$$avoidResync ? $location.url() : undefined; - if (options && options.replace) $location.replace(); - }, - - /** - * @ngdoc function - * @name ui.router.router.$urlRouter#href - * @methodOf ui.router.router.$urlRouter - * - * @description - * A URL generation method that returns the compiled URL for a given - * {@link ui.router.util.type:UrlMatcher `UrlMatcher`}, populated with the provided parameters. - * - * @example - *
-       * $bob = $urlRouter.href(new UrlMatcher("/about/:person"), {
-       *   person: "bob"
-       * });
-       * // $bob == "/about/bob";
-       * 
- * - * @param {UrlMatcher} urlMatcher The `UrlMatcher` object which is used as the template of the URL to generate. - * @param {object=} params An object of parameter values to fill the matcher's required parameters. - * @param {object=} options Options object. The options are: - * - * - **`absolute`** - {boolean=false}, If true will generate an absolute url, e.g. "http://www.example.com/fullurl". - * - * @returns {string} Returns the fully compiled URL, or `null` if `params` fail validation against `urlMatcher` - */ - href: function(urlMatcher, params, options) { - if (!urlMatcher.validates(params)) return null; - - var isHtml5 = $locationProvider.html5Mode(); - if (angular.isObject(isHtml5)) { - isHtml5 = isHtml5.enabled; - } - - var url = urlMatcher.format(params); - options = options || {}; - - if (!isHtml5 && url !== null) { - url = "#" + $locationProvider.hashPrefix() + url; - } - url = appendBasePath(url, isHtml5, options.absolute); - - if (!options.absolute || !url) { - return url; - } - - var slash = (!isHtml5 && url ? '/' : ''), port = $location.port(); - port = (port === 80 || port === 443 ? '' : ':' + port); - - return [$location.protocol(), '://', $location.host(), port, slash, url].join(''); - } - }; - } -} - -angular.module('ui.router.router').provider('$urlRouter', $UrlRouterProvider); - -/** - * @ngdoc object - * @name ui.router.state.$stateProvider - * - * @requires ui.router.router.$urlRouterProvider - * @requires ui.router.util.$urlMatcherFactoryProvider - * - * @description - * The new `$stateProvider` works similar to Angular's v1 router, but it focuses purely - * on state. - * - * A state corresponds to a "place" in the application in terms of the overall UI and - * navigation. A state describes (via the controller / template / view properties) what - * the UI looks like and does at that place. - * - * States often have things in common, and the primary way of factoring out these - * commonalities in this model is via the state hierarchy, i.e. parent/child states aka - * nested states. - * - * The `$stateProvider` provides interfaces to declare these states for your app. - */ -$StateProvider.$inject = ['$urlRouterProvider', '$urlMatcherFactoryProvider']; -function $StateProvider( $urlRouterProvider, $urlMatcherFactory) { - - var root, states = {}, $state, queue = {}, abstractKey = 'abstract'; - - // Builds state properties from definition passed to registerState() - var stateBuilder = { - - // Derive parent state from a hierarchical name only if 'parent' is not explicitly defined. - // state.children = []; - // if (parent) parent.children.push(state); - parent: function(state) { - if (isDefined(state.parent) && state.parent) return findState(state.parent); - // regex matches any valid composite state name - // would match "contact.list" but not "contacts" - var compositeName = /^(.+)\.[^.]+$/.exec(state.name); - return compositeName ? findState(compositeName[1]) : root; - }, - - // inherit 'data' from parent and override by own values (if any) - data: function(state) { - if (state.parent && state.parent.data) { - state.data = state.self.data = extend({}, state.parent.data, state.data); - } - return state.data; - }, - - // Build a URLMatcher if necessary, either via a relative or absolute URL - url: function(state) { - var url = state.url, config = { params: state.params || {} }; - - if (isString(url)) { - if (url.charAt(0) == '^') return $urlMatcherFactory.compile(url.substring(1), config); - return (state.parent.navigable || root).url.concat(url, config); - } - - if (!url || $urlMatcherFactory.isMatcher(url)) return url; - throw new Error("Invalid url '" + url + "' in state '" + state + "'"); - }, - - // Keep track of the closest ancestor state that has a URL (i.e. is navigable) - navigable: function(state) { - return state.url ? state : (state.parent ? state.parent.navigable : null); - }, - - // Own parameters for this state. state.url.params is already built at this point. Create and add non-url params - ownParams: function(state) { - var params = state.url && state.url.params || new $$UMFP.ParamSet(); - forEach(state.params || {}, function(config, id) { - if (!params[id]) params[id] = new $$UMFP.Param(id, null, config, "config"); - }); - return params; - }, - - // Derive parameters for this state and ensure they're a super-set of parent's parameters - params: function(state) { - return state.parent && state.parent.params ? extend(state.parent.params.$$new(), state.ownParams) : new $$UMFP.ParamSet(); - }, - - // If there is no explicit multi-view configuration, make one up so we don't have - // to handle both cases in the view directive later. Note that having an explicit - // 'views' property will mean the default unnamed view properties are ignored. This - // is also a good time to resolve view names to absolute names, so everything is a - // straight lookup at link time. - views: function(state) { - var views = {}; - - forEach(isDefined(state.views) ? state.views : { '': state }, function (view, name) { - if (name.indexOf('@') < 0) name += '@' + state.parent.name; - views[name] = view; - }); - return views; - }, - - // Keep a full path from the root down to this state as this is needed for state activation. - path: function(state) { - return state.parent ? state.parent.path.concat(state) : []; // exclude root from path - }, - - // Speed up $state.contains() as it's used a lot - includes: function(state) { - var includes = state.parent ? extend({}, state.parent.includes) : {}; - includes[state.name] = true; - return includes; - }, - - $delegates: {} - }; - - function isRelative(stateName) { - return stateName.indexOf(".") === 0 || stateName.indexOf("^") === 0; - } - - function findState(stateOrName, base) { - if (!stateOrName) return undefined; - - var isStr = isString(stateOrName), - name = isStr ? stateOrName : stateOrName.name, - path = isRelative(name); - - if (path) { - if (!base) throw new Error("No reference point given for path '" + name + "'"); - base = findState(base); - - var rel = name.split("."), i = 0, pathLength = rel.length, current = base; - - for (; i < pathLength; i++) { - if (rel[i] === "" && i === 0) { - current = base; - continue; - } - if (rel[i] === "^") { - if (!current.parent) throw new Error("Path '" + name + "' not valid for state '" + base.name + "'"); - current = current.parent; - continue; - } - break; - } - rel = rel.slice(i).join("."); - name = current.name + (current.name && rel ? "." : "") + rel; - } - var state = states[name]; - - if (state && (isStr || (!isStr && (state === stateOrName || state.self === stateOrName)))) { - return state; - } - return undefined; - } - - function queueState(parentName, state) { - if (!queue[parentName]) { - queue[parentName] = []; - } - queue[parentName].push(state); - } - - function flushQueuedChildren(parentName) { - var queued = queue[parentName] || []; - while(queued.length) { - registerState(queued.shift()); - } - } - - function registerState(state) { - // Wrap a new object around the state so we can store our private details easily. - state = inherit(state, { - self: state, - resolve: state.resolve || {}, - toString: function() { return this.name; } - }); - - var name = state.name; - if (!isString(name) || name.indexOf('@') >= 0) throw new Error("State must have a valid name"); - if (states.hasOwnProperty(name)) throw new Error("State '" + name + "'' is already defined"); - - // Get parent name - var parentName = (name.indexOf('.') !== -1) ? name.substring(0, name.lastIndexOf('.')) - : (isString(state.parent)) ? state.parent - : (isObject(state.parent) && isString(state.parent.name)) ? state.parent.name - : ''; - - // If parent is not registered yet, add state to queue and register later - if (parentName && !states[parentName]) { - return queueState(parentName, state.self); - } - - for (var key in stateBuilder) { - if (isFunction(stateBuilder[key])) state[key] = stateBuilder[key](state, stateBuilder.$delegates[key]); - } - states[name] = state; - - // Register the state in the global state list and with $urlRouter if necessary. - if (!state[abstractKey] && state.url) { - $urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) { - if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) { - $state.transitionTo(state, $match, { inherit: true, location: false }); - } - }]); - } - - // Register any queued children - flushQueuedChildren(name); - - return state; - } - - // Checks text to see if it looks like a glob. - function isGlob (text) { - return text.indexOf('*') > -1; - } - - // Returns true if glob matches current $state name. - function doesStateMatchGlob (glob) { - var globSegments = glob.split('.'), - segments = $state.$current.name.split('.'); - - //match greedy starts - if (globSegments[0] === '**') { - segments = segments.slice(indexOf(segments, globSegments[1])); - segments.unshift('**'); - } - //match greedy ends - if (globSegments[globSegments.length - 1] === '**') { - segments.splice(indexOf(segments, globSegments[globSegments.length - 2]) + 1, Number.MAX_VALUE); - segments.push('**'); - } - - if (globSegments.length != segments.length) { - return false; - } - - //match single stars - for (var i = 0, l = globSegments.length; i < l; i++) { - if (globSegments[i] === '*') { - segments[i] = '*'; - } - } - - return segments.join('') === globSegments.join(''); - } - - - // Implicit root state that is always active - root = registerState({ - name: '', - url: '^', - views: null, - 'abstract': true - }); - root.navigable = null; - - - /** - * @ngdoc function - * @name ui.router.state.$stateProvider#decorator - * @methodOf ui.router.state.$stateProvider - * - * @description - * Allows you to extend (carefully) or override (at your own peril) the - * `stateBuilder` object used internally by `$stateProvider`. This can be used - * to add custom functionality to ui-router, for example inferring templateUrl - * based on the state name. - * - * When passing only a name, it returns the current (original or decorated) builder - * function that matches `name`. - * - * The builder functions that can be decorated are listed below. Though not all - * necessarily have a good use case for decoration, that is up to you to decide. - * - * In addition, users can attach custom decorators, which will generate new - * properties within the state's internal definition. There is currently no clear - * use-case for this beyond accessing internal states (i.e. $state.$current), - * however, expect this to become increasingly relevant as we introduce additional - * meta-programming features. - * - * **Warning**: Decorators should not be interdependent because the order of - * execution of the builder functions in non-deterministic. Builder functions - * should only be dependent on the state definition object and super function. - * - * - * Existing builder functions and current return values: - * - * - **parent** `{object}` - returns the parent state object. - * - **data** `{object}` - returns state data, including any inherited data that is not - * overridden by own values (if any). - * - **url** `{object}` - returns a {@link ui.router.util.type:UrlMatcher UrlMatcher} - * or `null`. - * - **navigable** `{object}` - returns closest ancestor state that has a URL (aka is - * navigable). - * - **params** `{object}` - returns an array of state params that are ensured to - * be a super-set of parent's params. - * - **views** `{object}` - returns a views object where each key is an absolute view - * name (i.e. "viewName@stateName") and each value is the config object - * (template, controller) for the view. Even when you don't use the views object - * explicitly on a state config, one is still created for you internally. - * So by decorating this builder function you have access to decorating template - * and controller properties. - * - **ownParams** `{object}` - returns an array of params that belong to the state, - * not including any params defined by ancestor states. - * - **path** `{string}` - returns the full path from the root down to this state. - * Needed for state activation. - * - **includes** `{object}` - returns an object that includes every state that - * would pass a `$state.includes()` test. - * - * @example - *
-   * // Override the internal 'views' builder with a function that takes the state
-   * // definition, and a reference to the internal function being overridden:
-   * $stateProvider.decorator('views', function (state, parent) {
-   *   var result = {},
-   *       views = parent(state);
-   *
-   *   angular.forEach(views, function (config, name) {
-   *     var autoName = (state.name + '.' + name).replace('.', '/');
-   *     config.templateUrl = config.templateUrl || '/partials/' + autoName + '.html';
-   *     result[name] = config;
-   *   });
-   *   return result;
-   * });
-   *
-   * $stateProvider.state('home', {
-   *   views: {
-   *     'contact.list': { controller: 'ListController' },
-   *     'contact.item': { controller: 'ItemController' }
-   *   }
-   * });
-   *
-   * // ...
-   *
-   * $state.go('home');
-   * // Auto-populates list and item views with /partials/home/contact/list.html,
-   * // and /partials/home/contact/item.html, respectively.
-   * 
- * - * @param {string} name The name of the builder function to decorate. - * @param {object} func A function that is responsible for decorating the original - * builder function. The function receives two parameters: - * - * - `{object}` - state - The state config object. - * - `{object}` - super - The original builder function. - * - * @return {object} $stateProvider - $stateProvider instance - */ - this.decorator = decorator; - function decorator(name, func) { - /*jshint validthis: true */ - if (isString(name) && !isDefined(func)) { - return stateBuilder[name]; - } - if (!isFunction(func) || !isString(name)) { - return this; - } - if (stateBuilder[name] && !stateBuilder.$delegates[name]) { - stateBuilder.$delegates[name] = stateBuilder[name]; - } - stateBuilder[name] = func; - return this; - } - - /** - * @ngdoc function - * @name ui.router.state.$stateProvider#state - * @methodOf ui.router.state.$stateProvider - * - * @description - * Registers a state configuration under a given state name. The stateConfig object - * has the following acceptable properties. - * - * @param {string} name A unique state name, e.g. "home", "about", "contacts". - * To create a parent/child state use a dot, e.g. "about.sales", "home.newest". - * @param {object} stateConfig State configuration object. - * @param {string|function=} stateConfig.template - * - * html template as a string or a function that returns - * an html template as a string which should be used by the uiView directives. This property - * takes precedence over templateUrl. - * - * If `template` is a function, it will be called with the following parameters: - * - * - {array.<object>} - state parameters extracted from the current $location.path() by - * applying the current state - * - *
template:
-   *   "

inline template definition

" + - * "
"
- *
template: function(params) {
-   *       return "

generated template

"; }
- * - * - * @param {string|function=} stateConfig.templateUrl - * - * - * path or function that returns a path to an html - * template that should be used by uiView. - * - * If `templateUrl` is a function, it will be called with the following parameters: - * - * - {array.<object>} - state parameters extracted from the current $location.path() by - * applying the current state - * - *
templateUrl: "home.html"
- *
templateUrl: function(params) {
-   *     return myTemplates[params.pageId]; }
- * - * @param {function=} stateConfig.templateProvider - * - * Provider function that returns HTML content string. - *
 templateProvider:
-   *       function(MyTemplateService, params) {
-   *         return MyTemplateService.getTemplate(params.pageId);
-   *       }
- * - * @param {string|function=} stateConfig.controller - * - * - * Controller fn that should be associated with newly - * related scope or the name of a registered controller if passed as a string. - * Optionally, the ControllerAs may be declared here. - *
controller: "MyRegisteredController"
- *
controller:
-   *     "MyRegisteredController as fooCtrl"}
- *
controller: function($scope, MyService) {
-   *     $scope.data = MyService.getData(); }
- * - * @param {function=} stateConfig.controllerProvider - * - * - * Injectable provider function that returns the actual controller or string. - *
controllerProvider:
-   *   function(MyResolveData) {
-   *     if (MyResolveData.foo)
-   *       return "FooCtrl"
-   *     else if (MyResolveData.bar)
-   *       return "BarCtrl";
-   *     else return function($scope) {
-   *       $scope.baz = "Qux";
-   *     }
-   *   }
- * - * @param {string=} stateConfig.controllerAs - * - * - * A controller alias name. If present the controller will be - * published to scope under the controllerAs name. - *
controllerAs: "myCtrl"
- * - * @param {object=} stateConfig.resolve - * - * - * An optional map<string, function> 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 before the controller is instantiated. - * If all the promises are resolved successfully, the $stateChangeSuccess event is fired - * and the values of the resolved promises are injected into any controllers that reference them. - * If any of the promises are rejected the $stateChangeError event is fired. - * - * The map object is: - * - * - key - {string}: name of dependency to be injected into controller - * - factory - {string|function}: If string then it is alias for service. Otherwise if function, - * it is injected and return value it treated as dependency. If result is a promise, it is - * resolved before its value is injected into controller. - * - *
resolve: {
-   *     myResolve1:
-   *       function($http, $stateParams) {
-   *         return $http.get("/api/foos/"+stateParams.fooID);
-   *       }
-   *     }
- * - * @param {string=} stateConfig.url - * - * - * A url fragment with optional parameters. When a state is navigated or - * transitioned to, the `$stateParams` service will be populated with any - * parameters that were passed. - * - * examples: - *
url: "/home"
-   * url: "/users/:userid"
-   * url: "/books/{bookid:[a-zA-Z_-]}"
-   * url: "/books/{categoryid:int}"
-   * url: "/books/{publishername:string}/{categoryid:int}"
-   * url: "/messages?before&after"
-   * url: "/messages?{before:date}&{after:date}"
- * url: "/messages/:mailboxid?{before:date}&{after:date}" - * - * @param {object=} stateConfig.views - * - * an optional map<string, object> which defined multiple views, or targets views - * manually/explicitly. - * - * Examples: - * - * Targets three named `ui-view`s in the parent state's template - *
views: {
-   *     header: {
-   *       controller: "headerCtrl",
-   *       templateUrl: "header.html"
-   *     }, body: {
-   *       controller: "bodyCtrl",
-   *       templateUrl: "body.html"
-   *     }, footer: {
-   *       controller: "footCtrl",
-   *       templateUrl: "footer.html"
-   *     }
-   *   }
- * - * Targets named `ui-view="header"` from grandparent state 'top''s template, and named `ui-view="body" from parent state's template. - *
views: {
-   *     'header@top': {
-   *       controller: "msgHeaderCtrl",
-   *       templateUrl: "msgHeader.html"
-   *     }, 'body': {
-   *       controller: "messagesCtrl",
-   *       templateUrl: "messages.html"
-   *     }
-   *   }
- * - * @param {boolean=} [stateConfig.abstract=false] - * - * An abstract state will never be directly activated, - * but can provide inherited properties to its common children states. - *
abstract: true
- * - * @param {function=} stateConfig.onEnter - * - * - * Callback function for when a state is entered. Good way - * to trigger an action or dispatch an event, such as opening a dialog. - * If minifying your scripts, make sure to explictly annotate this function, - * because it won't be automatically annotated by your build tools. - * - *
onEnter: function(MyService, $stateParams) {
-   *     MyService.foo($stateParams.myParam);
-   * }
- * - * @param {function=} stateConfig.onExit - * - * - * Callback function for when a state is exited. Good way to - * trigger an action or dispatch an event, such as opening a dialog. - * If minifying your scripts, make sure to explictly annotate this function, - * because it won't be automatically annotated by your build tools. - * - *
onExit: function(MyService, $stateParams) {
-   *     MyService.cleanup($stateParams.myParam);
-   * }
- * - * @param {boolean=} [stateConfig.reloadOnSearch=true] - * - * - * If `false`, will not retrigger the same state - * just because a search/query parameter has changed (via $location.search() or $location.hash()). - * Useful for when you'd like to modify $location.search() without triggering a reload. - *
reloadOnSearch: false
- * - * @param {object=} stateConfig.data - * - * - * Arbitrary data object, useful for custom configuration. The parent state's `data` is - * prototypally inherited. In other words, adding a data property to a state adds it to - * the entire subtree via prototypal inheritance. - * - *
data: {
-   *     requiredRole: 'foo'
-   * } 
- * - * @param {object=} stateConfig.params - * - * - * A map which optionally configures parameters declared in the `url`, or - * defines additional non-url parameters. For each parameter being - * configured, add a configuration object keyed to the name of the parameter. - * - * Each parameter configuration object may contain the following properties: - * - * - ** value ** - {object|function=}: specifies the default value for this - * parameter. This implicitly sets this parameter as optional. - * - * When UI-Router routes to a state and no value is - * specified for this parameter in the URL or transition, the - * default value will be used instead. If `value` is a function, - * it will be injected and invoked, and the return value used. - * - * *Note*: `undefined` is treated as "no default value" while `null` - * is treated as "the default value is `null`". - * - * *Shorthand*: If you only need to configure the default value of the - * parameter, you may use a shorthand syntax. In the **`params`** - * map, instead mapping the param name to a full parameter configuration - * object, simply set map it to the default parameter value, e.g.: - * - *
// define a parameter's default value
-   * params: {
-   *     param1: { value: "defaultValue" }
-   * }
-   * // shorthand default values
-   * params: {
-   *     param1: "defaultValue",
-   *     param2: "param2Default"
-   * }
- * - * - ** array ** - {boolean=}: *(default: false)* If true, the param value will be - * treated as an array of values. If you specified a Type, the value will be - * treated as an array of the specified Type. Note: query parameter values - * default to a special `"auto"` mode. - * - * For query parameters in `"auto"` mode, if multiple values for a single parameter - * are present in the URL (e.g.: `/foo?bar=1&bar=2&bar=3`) then the values - * are mapped to an array (e.g.: `{ foo: [ '1', '2', '3' ] }`). However, if - * only one value is present (e.g.: `/foo?bar=1`) then the value is treated as single - * value (e.g.: `{ foo: '1' }`). - * - *
params: {
-   *     param1: { array: true }
-   * }
- * - * - ** squash ** - {bool|string=}: `squash` configures how a default parameter value is represented in the URL when - * the current parameter value is the same as the default value. If `squash` is not set, it uses the - * configured default squash policy. - * (See {@link ui.router.util.$urlMatcherFactory#methods_defaultSquashPolicy `defaultSquashPolicy()`}) - * - * There are three squash settings: - * - * - false: The parameter's default value is not squashed. It is encoded and included in the URL - * - true: The parameter's default value is omitted from the URL. If the parameter is preceeded and followed - * by slashes in the state's `url` declaration, then one of those slashes are omitted. - * This can allow for cleaner looking URLs. - * - `""`: The parameter's default value is replaced with an arbitrary placeholder of your choice. - * - *
params: {
-   *     param1: {
-   *       value: "defaultId",
-   *       squash: true
-   * } }
-   * // squash "defaultValue" to "~"
-   * params: {
-   *     param1: {
-   *       value: "defaultValue",
-   *       squash: "~"
-   * } }
-   * 
- * - * - * @example - *
-   * // Some state name examples
-   *
-   * // stateName can be a single top-level name (must be unique).
-   * $stateProvider.state("home", {});
-   *
-   * // Or it can be a nested state name. This state is a child of the
-   * // above "home" state.
-   * $stateProvider.state("home.newest", {});
-   *
-   * // Nest states as deeply as needed.
-   * $stateProvider.state("home.newest.abc.xyz.inception", {});
-   *
-   * // state() returns $stateProvider, so you can chain state declarations.
-   * $stateProvider
-   *   .state("home", {})
-   *   .state("about", {})
-   *   .state("contacts", {});
-   * 
- * - */ - this.state = state; - function state(name, definition) { - /*jshint validthis: true */ - if (isObject(name)) definition = name; - else definition.name = name; - registerState(definition); - return this; - } - - /** - * @ngdoc object - * @name ui.router.state.$state - * - * @requires $rootScope - * @requires $q - * @requires ui.router.state.$view - * @requires $injector - * @requires ui.router.util.$resolve - * @requires ui.router.state.$stateParams - * @requires ui.router.router.$urlRouter - * - * @property {object} params A param object, e.g. {sectionId: section.id)}, that - * you'd like to test against the current active state. - * @property {object} current A reference to the state's config object. However - * you passed it in. Useful for accessing custom data. - * @property {object} transition Currently pending transition. A promise that'll - * resolve or reject. - * - * @description - * `$state` service is responsible for representing states as well as transitioning - * between them. It also provides interfaces to ask for current state or even states - * you're coming from. - */ - this.$get = $get; - $get.$inject = ['$rootScope', '$q', '$view', '$injector', '$resolve', '$stateParams', '$urlRouter', '$location', '$urlMatcherFactory']; - function $get( $rootScope, $q, $view, $injector, $resolve, $stateParams, $urlRouter, $location, $urlMatcherFactory) { - - var TransitionSuperseded = $q.reject(new Error('transition superseded')); - var TransitionPrevented = $q.reject(new Error('transition prevented')); - var TransitionAborted = $q.reject(new Error('transition aborted')); - var TransitionFailed = $q.reject(new Error('transition failed')); - - // Handles the case where a state which is the target of a transition is not found, and the user - // can optionally retry or defer the transition - function handleRedirect(redirect, state, params, options) { - /** - * @ngdoc event - * @name ui.router.state.$state#$stateNotFound - * @eventOf ui.router.state.$state - * @eventType broadcast on root scope - * @description - * Fired when a requested state **cannot be found** using the provided state name during transition. - * The event is broadcast allowing any handlers a single chance to deal with the error (usually by - * lazy-loading the unfound state). A special `unfoundState` object is passed to the listener handler, - * you can see its three properties in the example. You can use `event.preventDefault()` to abort the - * transition and the promise returned from `go` will be rejected with a `'transition aborted'` value. - * - * @param {Object} event Event object. - * @param {Object} unfoundState Unfound State information. Contains: `to, toParams, options` properties. - * @param {State} fromState Current state object. - * @param {Object} fromParams Current state params. - * - * @example - * - *
-       * // somewhere, assume lazy.state has not been defined
-       * $state.go("lazy.state", {a:1, b:2}, {inherit:false});
-       *
-       * // somewhere else
-       * $scope.$on('$stateNotFound',
-       * function(event, unfoundState, fromState, fromParams){
-       *     console.log(unfoundState.to); // "lazy.state"
-       *     console.log(unfoundState.toParams); // {a:1, b:2}
-       *     console.log(unfoundState.options); // {inherit:false} + default options
-       * })
-       * 
- */ - var evt = $rootScope.$broadcast('$stateNotFound', redirect, state, params); - - if (evt.defaultPrevented) { - $urlRouter.update(); - return TransitionAborted; - } - - if (!evt.retry) { - return null; - } - - // Allow the handler to return a promise to defer state lookup retry - if (options.$retry) { - $urlRouter.update(); - return TransitionFailed; - } - var retryTransition = $state.transition = $q.when(evt.retry); - - retryTransition.then(function() { - if (retryTransition !== $state.transition) return TransitionSuperseded; - redirect.options.$retry = true; - return $state.transitionTo(redirect.to, redirect.toParams, redirect.options); - }, function() { - return TransitionAborted; - }); - $urlRouter.update(); - - return retryTransition; - } - - root.locals = { resolve: null, globals: { $stateParams: {} } }; - - $state = { - params: {}, - current: root.self, - $current: root, - transition: null - }; - - /** - * @ngdoc function - * @name ui.router.state.$state#reload - * @methodOf ui.router.state.$state - * - * @description - * A method that force reloads the current state. All resolves are re-resolved, events are not re-fired, - * and controllers reinstantiated (bug with controllers reinstantiating right now, fixing soon). - * - * @example - *
-     * var app angular.module('app', ['ui.router']);
-     *
-     * app.controller('ctrl', function ($scope, $state) {
-     *   $scope.reload = function(){
-     *     $state.reload();
-     *   }
-     * });
-     * 
- * - * `reload()` is just an alias for: - *
-     * $state.transitionTo($state.current, $stateParams, { 
-     *   reload: true, inherit: false, notify: true
-     * });
-     * 
- * - * @returns {promise} A promise representing the state of the new transition. See - * {@link ui.router.state.$state#methods_go $state.go}. - */ - $state.reload = function reload() { - return $state.transitionTo($state.current, $stateParams, { reload: true, inherit: false, notify: true }); - }; - - /** - * @ngdoc function - * @name ui.router.state.$state#go - * @methodOf ui.router.state.$state - * - * @description - * Convenience method for transitioning to a new state. `$state.go` calls - * `$state.transitionTo` internally but automatically sets options to - * `{ location: true, inherit: true, relative: $state.$current, notify: true }`. - * This allows you to easily use an absolute or relative to path and specify - * only the parameters you'd like to update (while letting unspecified parameters - * inherit from the currently active ancestor states). - * - * @example - *
-     * var app = angular.module('app', ['ui.router']);
-     *
-     * app.controller('ctrl', function ($scope, $state) {
-     *   $scope.changeState = function () {
-     *     $state.go('contact.detail');
-     *   };
-     * });
-     * 
- * - * - * @param {string} to Absolute state name or relative state path. Some examples: - * - * - `$state.go('contact.detail')` - will go to the `contact.detail` state - * - `$state.go('^')` - will go to a parent state - * - `$state.go('^.sibling')` - will go to a sibling state - * - `$state.go('.child.grandchild')` - will go to grandchild state - * - * @param {object=} params A map of the parameters that will be sent to the state, - * will populate $stateParams. Any parameters that are not specified will be inherited from currently - * defined parameters. This allows, for example, going to a sibling state that shares parameters - * specified in a parent state. Parameter inheritance only works between common ancestor states, I.e. - * transitioning to a sibling will get you the parameters for all parents, transitioning to a child - * will get you all current parameters, etc. - * @param {object=} options Options object. The options are: - * - * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false` - * will not. If string, must be `"replace"`, which will update url and also replace last history record. - * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url. - * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), - * defines which state to be relative from. - * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events. - * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params - * have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd - * use this when you want to force a reload when *everything* is the same, including search params. - * - * @returns {promise} A promise representing the state of the new transition. - * - * Possible success values: - * - * - $state.current - * - *
Possible rejection values: - * - * - 'transition superseded' - when a newer transition has been started after this one - * - 'transition prevented' - when `event.preventDefault()` has been called in a `$stateChangeStart` listener - * - 'transition aborted' - when `event.preventDefault()` has been called in a `$stateNotFound` listener or - * when a `$stateNotFound` `event.retry` promise errors. - * - 'transition failed' - when a state has been unsuccessfully found after 2 tries. - * - *resolve error* - when an error has occurred with a `resolve` - * - */ - $state.go = function go(to, params, options) { - return $state.transitionTo(to, params, extend({ inherit: true, relative: $state.$current }, options)); - }; - - /** - * @ngdoc function - * @name ui.router.state.$state#transitionTo - * @methodOf ui.router.state.$state - * - * @description - * Low-level method for transitioning to a new state. {@link ui.router.state.$state#methods_go $state.go} - * uses `transitionTo` internally. `$state.go` is recommended in most situations. - * - * @example - *
-     * var app = angular.module('app', ['ui.router']);
-     *
-     * app.controller('ctrl', function ($scope, $state) {
-     *   $scope.changeState = function () {
-     *     $state.transitionTo('contact.detail');
-     *   };
-     * });
-     * 
- * - * @param {string} to State name. - * @param {object=} toParams A map of the parameters that will be sent to the state, - * will populate $stateParams. - * @param {object=} options Options object. The options are: - * - * - **`location`** - {boolean=true|string=} - If `true` will update the url in the location bar, if `false` - * will not. If string, must be `"replace"`, which will update url and also replace last history record. - * - **`inherit`** - {boolean=false}, If `true` will inherit url parameters from current url. - * - **`relative`** - {object=}, When transitioning with relative path (e.g '^'), - * defines which state to be relative from. - * - **`notify`** - {boolean=true}, If `true` will broadcast $stateChangeStart and $stateChangeSuccess events. - * - **`reload`** (v0.2.5) - {boolean=false}, If `true` will force transition even if the state or params - * have not changed, aka a reload of the same state. It differs from reloadOnSearch because you'd - * use this when you want to force a reload when *everything* is the same, including search params. - * - * @returns {promise} A promise representing the state of the new transition. See - * {@link ui.router.state.$state#methods_go $state.go}. - */ - $state.transitionTo = function transitionTo(to, toParams, options) { - toParams = toParams || {}; - options = extend({ - location: true, inherit: false, relative: null, notify: true, reload: false, $retry: false - }, options || {}); - - var from = $state.$current, fromParams = $state.params, fromPath = from.path; - var evt, toState = findState(to, options.relative); - - if (!isDefined(toState)) { - var redirect = { to: to, toParams: toParams, options: options }; - var redirectResult = handleRedirect(redirect, from.self, fromParams, options); - - if (redirectResult) { - return redirectResult; - } - - // Always retry once if the $stateNotFound was not prevented - // (handles either redirect changed or state lazy-definition) - to = redirect.to; - toParams = redirect.toParams; - options = redirect.options; - toState = findState(to, options.relative); - - if (!isDefined(toState)) { - if (!options.relative) throw new Error("No such state '" + to + "'"); - throw new Error("Could not resolve '" + to + "' from state '" + options.relative + "'"); - } - } - if (toState[abstractKey]) throw new Error("Cannot transition to abstract state '" + to + "'"); - if (options.inherit) toParams = inheritParams($stateParams, toParams || {}, $state.$current, toState); - if (!toState.params.$$validates(toParams)) return TransitionFailed; - - toParams = toState.params.$$values(toParams); - to = toState; - - var toPath = to.path; - - // Starting from the root of the path, keep all levels that haven't changed - var keep = 0, state = toPath[keep], locals = root.locals, toLocals = []; - - if (!options.reload) { - while (state && state === fromPath[keep] && state.ownParams.$$equals(toParams, fromParams)) { - locals = toLocals[keep] = state.locals; - keep++; - state = toPath[keep]; - } - } - - // If we're going to the same state and all locals are kept, we've got nothing to do. - // But clear 'transition', as we still want to cancel any other pending transitions. - // TODO: We may not want to bump 'transition' if we're called from a location change - // that we've initiated ourselves, because we might accidentally abort a legitimate - // transition initiated from code? - if (shouldTriggerReload(to, from, locals, options)) { - if (to.self.reloadOnSearch !== false) $urlRouter.update(); - $state.transition = null; - return $q.when($state.current); - } - - // Filter parameters before we pass them to event handlers etc. - toParams = filterByKeys(to.params.$$keys(), toParams || {}); - - // Broadcast start event and cancel the transition if requested - if (options.notify) { - /** - * @ngdoc event - * @name ui.router.state.$state#$stateChangeStart - * @eventOf ui.router.state.$state - * @eventType broadcast on root scope - * @description - * Fired when the state transition **begins**. You can use `event.preventDefault()` - * to prevent the transition from happening and then the transition promise will be - * rejected with a `'transition prevented'` value. - * - * @param {Object} event Event object. - * @param {State} toState The state being transitioned to. - * @param {Object} toParams The params supplied to the `toState`. - * @param {State} fromState The current state, pre-transition. - * @param {Object} fromParams The params supplied to the `fromState`. - * - * @example - * - *
-         * $rootScope.$on('$stateChangeStart',
-         * function(event, toState, toParams, fromState, fromParams){
-         *     event.preventDefault();
-         *     // transitionTo() promise will be rejected with
-         *     // a 'transition prevented' error
-         * })
-         * 
- */ - if ($rootScope.$broadcast('$stateChangeStart', to.self, toParams, from.self, fromParams).defaultPrevented) { - $urlRouter.update(); - return TransitionPrevented; - } - } - - // Resolve locals for the remaining states, but don't update any global state just - // yet -- if anything fails to resolve the current state needs to remain untouched. - // We also set up an inheritance chain for the locals here. This allows the view directive - // to quickly look up the correct definition for each view in the current state. Even - // though we create the locals object itself outside resolveState(), it is initially - // empty and gets filled asynchronously. We need to keep track of the promise for the - // (fully resolved) current locals, and pass this down the chain. - var resolved = $q.when(locals); - - for (var l = keep; l < toPath.length; l++, state = toPath[l]) { - locals = toLocals[l] = inherit(locals); - resolved = resolveState(state, toParams, state === to, resolved, locals, options); - } - - // Once everything is resolved, we are ready to perform the actual transition - // and return a promise for the new state. We also keep track of what the - // current promise is, so that we can detect overlapping transitions and - // keep only the outcome of the last transition. - var transition = $state.transition = resolved.then(function () { - var l, entering, exiting; - - if ($state.transition !== transition) return TransitionSuperseded; - - // Exit 'from' states not kept - for (l = fromPath.length - 1; l >= keep; l--) { - exiting = fromPath[l]; - if (exiting.self.onExit) { - $injector.invoke(exiting.self.onExit, exiting.self, exiting.locals.globals); - } - exiting.locals = null; - } - - // Enter 'to' states not kept - for (l = keep; l < toPath.length; l++) { - entering = toPath[l]; - entering.locals = toLocals[l]; - if (entering.self.onEnter) { - $injector.invoke(entering.self.onEnter, entering.self, entering.locals.globals); - } - } - - // Run it again, to catch any transitions in callbacks - if ($state.transition !== transition) return TransitionSuperseded; - - // Update globals in $state - $state.$current = to; - $state.current = to.self; - $state.params = toParams; - copy($state.params, $stateParams); - $state.transition = null; - - if (options.location && to.navigable) { - $urlRouter.push(to.navigable.url, to.navigable.locals.globals.$stateParams, { - $$avoidResync: true, replace: options.location === 'replace' - }); - } - - if (options.notify) { - /** - * @ngdoc event - * @name ui.router.state.$state#$stateChangeSuccess - * @eventOf ui.router.state.$state - * @eventType broadcast on root scope - * @description - * Fired once the state transition is **complete**. - * - * @param {Object} event Event object. - * @param {State} toState The state being transitioned to. - * @param {Object} toParams The params supplied to the `toState`. - * @param {State} fromState The current state, pre-transition. - * @param {Object} fromParams The params supplied to the `fromState`. - */ - $rootScope.$broadcast('$stateChangeSuccess', to.self, toParams, from.self, fromParams); - } - $urlRouter.update(true); - - return $state.current; - }, function (error) { - if ($state.transition !== transition) return TransitionSuperseded; - - $state.transition = null; - /** - * @ngdoc event - * @name ui.router.state.$state#$stateChangeError - * @eventOf ui.router.state.$state - * @eventType broadcast on root scope - * @description - * Fired when an **error occurs** during transition. It's important to note that if you - * have any errors in your resolve functions (javascript errors, non-existent services, etc) - * they will not throw traditionally. You must listen for this $stateChangeError event to - * catch **ALL** errors. - * - * @param {Object} event Event object. - * @param {State} toState The state being transitioned to. - * @param {Object} toParams The params supplied to the `toState`. - * @param {State} fromState The current state, pre-transition. - * @param {Object} fromParams The params supplied to the `fromState`. - * @param {Error} error The resolve error object. - */ - evt = $rootScope.$broadcast('$stateChangeError', to.self, toParams, from.self, fromParams, error); - - if (!evt.defaultPrevented) { - $urlRouter.update(); - } - - return $q.reject(error); - }); - - return transition; - }; - - /** - * @ngdoc function - * @name ui.router.state.$state#is - * @methodOf ui.router.state.$state - * - * @description - * Similar to {@link ui.router.state.$state#methods_includes $state.includes}, - * but only checks for the full state name. If params is supplied then it will be - * tested for strict equality against the current active params object, so all params - * must match with none missing and no extras. - * - * @example - *
-     * $state.$current.name = 'contacts.details.item';
-     *
-     * // absolute name
-     * $state.is('contact.details.item'); // returns true
-     * $state.is(contactDetailItemStateObject); // returns true
-     *
-     * // relative name (. and ^), typically from a template
-     * // E.g. from the 'contacts.details' template
-     * 
Item
- *
- * - * @param {string|object} stateOrName The state name (absolute or relative) or state object you'd like to check. - * @param {object=} params A param object, e.g. `{sectionId: section.id}`, that you'd like - * to test against the current active state. - * @param {object=} options An options object. The options are: - * - * - **`relative`** - {string|object} - If `stateOrName` is a relative state name and `options.relative` is set, .is will - * test relative to `options.relative` state (or name). - * - * @returns {boolean} Returns true if it is the state. - */ - $state.is = function is(stateOrName, params, options) { - options = extend({ relative: $state.$current }, options || {}); - var state = findState(stateOrName, options.relative); - - if (!isDefined(state)) { return undefined; } - if ($state.$current !== state) { return false; } - return params ? equalForKeys(state.params.$$values(params), $stateParams) : true; - }; - - /** - * @ngdoc function - * @name ui.router.state.$state#includes - * @methodOf ui.router.state.$state - * - * @description - * A method to determine if the current active state is equal to or is the child of the - * state stateName. If any params are passed then they will be tested for a match as well. - * Not all the parameters need to be passed, just the ones you'd like to test for equality. - * - * @example - * Partial and relative names - *
-     * $state.$current.name = 'contacts.details.item';
-     *
-     * // Using partial names
-     * $state.includes("contacts"); // returns true
-     * $state.includes("contacts.details"); // returns true
-     * $state.includes("contacts.details.item"); // returns true
-     * $state.includes("contacts.list"); // returns false
-     * $state.includes("about"); // returns false
-     *
-     * // Using relative names (. and ^), typically from a template
-     * // E.g. from the 'contacts.details' template
-     * 
Item
- *
- * - * Basic globbing patterns - *
-     * $state.$current.name = 'contacts.details.item.url';
-     *
-     * $state.includes("*.details.*.*"); // returns true
-     * $state.includes("*.details.**"); // returns true
-     * $state.includes("**.item.**"); // returns true
-     * $state.includes("*.details.item.url"); // returns true
-     * $state.includes("*.details.*.url"); // returns true
-     * $state.includes("*.details.*"); // returns false
-     * $state.includes("item.**"); // returns false
-     * 
- * - * @param {string} stateOrName A partial name, relative name, or glob pattern - * to be searched for within the current state name. - * @param {object=} params A param object, e.g. `{sectionId: section.id}`, - * that you'd like to test against the current active state. - * @param {object=} options An options object. The options are: - * - * - **`relative`** - {string|object=} - If `stateOrName` is a relative state reference and `options.relative` is set, - * .includes will test relative to `options.relative` state (or name). - * - * @returns {boolean} Returns true if it does include the state - */ - $state.includes = function includes(stateOrName, params, options) { - options = extend({ relative: $state.$current }, options || {}); - if (isString(stateOrName) && isGlob(stateOrName)) { - if (!doesStateMatchGlob(stateOrName)) { - return false; - } - stateOrName = $state.$current.name; - } - - var state = findState(stateOrName, options.relative); - if (!isDefined(state)) { return undefined; } - if (!isDefined($state.$current.includes[state.name])) { return false; } - return params ? equalForKeys(state.params.$$values(params), $stateParams, objectKeys(params)) : true; - }; - - - /** - * @ngdoc function - * @name ui.router.state.$state#href - * @methodOf ui.router.state.$state - * - * @description - * A url generation method that returns the compiled url for the given state populated with the given params. - * - * @example - *
-     * expect($state.href("about.person", { person: "bob" })).toEqual("/about/bob");
-     * 
- * - * @param {string|object} stateOrName The state name or state object you'd like to generate a url from. - * @param {object=} params An object of parameter values to fill the state's required parameters. - * @param {object=} options Options object. The options are: - * - * - **`lossy`** - {boolean=true} - If true, and if there is no url associated with the state provided in the - * first parameter, then the constructed href url will be built from the first navigable ancestor (aka - * ancestor with a valid url). - * - **`inherit`** - {boolean=true}, If `true` will inherit url parameters from current url. - * - **`relative`** - {object=$state.$current}, When transitioning with relative path (e.g '^'), - * defines which state to be relative from. - * - **`absolute`** - {boolean=false}, If true will generate an absolute url, e.g. "http://www.example.com/fullurl". - * - * @returns {string} compiled state url - */ - $state.href = function href(stateOrName, params, options) { - options = extend({ - lossy: true, - inherit: true, - absolute: false, - relative: $state.$current - }, options || {}); - - var state = findState(stateOrName, options.relative); - - if (!isDefined(state)) return null; - if (options.inherit) params = inheritParams($stateParams, params || {}, $state.$current, state); - - var nav = (state && options.lossy) ? state.navigable : state; - - if (!nav || nav.url === undefined || nav.url === null) { - return null; - } - return $urlRouter.href(nav.url, filterByKeys(state.params.$$keys(), params || {}), { - absolute: options.absolute - }); - }; - - /** - * @ngdoc function - * @name ui.router.state.$state#get - * @methodOf ui.router.state.$state - * - * @description - * Returns the state configuration object for any specific state or all states. - * - * @param {string|object=} stateOrName (absolute or relative) If provided, will only get the config for - * the requested state. If not provided, returns an array of ALL state configs. - * @param {string|object=} context When stateOrName is a relative state reference, the state will be retrieved relative to context. - * @returns {Object|Array} State configuration object or array of all objects. - */ - $state.get = function (stateOrName, context) { - if (arguments.length === 0) return map(objectKeys(states), function(name) { return states[name].self; }); - var state = findState(stateOrName, context || $state.$current); - return (state && state.self) ? state.self : null; - }; - - function resolveState(state, params, paramsAreFiltered, inherited, dst, options) { - // Make a restricted $stateParams with only the parameters that apply to this state if - // necessary. In addition to being available to the controller and onEnter/onExit callbacks, - // we also need $stateParams to be available for any $injector calls we make during the - // dependency resolution process. - var $stateParams = (paramsAreFiltered) ? params : filterByKeys(state.params.$$keys(), params); - var locals = { $stateParams: $stateParams }; - - // Resolve 'global' dependencies for the state, i.e. those not specific to a view. - // We're also including $stateParams in this; that way the parameters are restricted - // to the set that should be visible to the state, and are independent of when we update - // the global $state and $stateParams values. - dst.resolve = $resolve.resolve(state.resolve, locals, dst.resolve, state); - var promises = [dst.resolve.then(function (globals) { - dst.globals = globals; - })]; - if (inherited) promises.push(inherited); - - // Resolve template and dependencies for all views. - forEach(state.views, function (view, name) { - var injectables = (view.resolve && view.resolve !== state.resolve ? view.resolve : {}); - injectables.$template = [ function () { - return $view.load(name, { view: view, locals: locals, params: $stateParams, notify: options.notify }) || ''; - }]; - - promises.push($resolve.resolve(injectables, locals, dst.resolve, state).then(function (result) { - // References to the controller (only instantiated at link time) - if (isFunction(view.controllerProvider) || isArray(view.controllerProvider)) { - var injectLocals = angular.extend({}, injectables, locals); - result.$$controller = $injector.invoke(view.controllerProvider, null, injectLocals); - } else { - result.$$controller = view.controller; - } - // Provide access to the state itself for internal use - result.$$state = state; - result.$$controllerAs = view.controllerAs; - dst[name] = result; - })); - }); - - // Wait for all the promises and then return the activation object - return $q.all(promises).then(function (values) { - return dst; - }); - } - - return $state; - } - - function shouldTriggerReload(to, from, locals, options) { - if (to === from && ((locals === from.locals && !options.reload) || (to.self.reloadOnSearch === false))) { - return true; - } - } -} - -angular.module('ui.router.state') - .value('$stateParams', {}) - .provider('$state', $StateProvider); - - -$ViewProvider.$inject = []; -function $ViewProvider() { - - this.$get = $get; - /** - * @ngdoc object - * @name ui.router.state.$view - * - * @requires ui.router.util.$templateFactory - * @requires $rootScope - * - * @description - * - */ - $get.$inject = ['$rootScope', '$templateFactory']; - function $get( $rootScope, $templateFactory) { - return { - // $view.load('full.viewName', { template: ..., controller: ..., resolve: ..., async: false, params: ... }) - /** - * @ngdoc function - * @name ui.router.state.$view#load - * @methodOf ui.router.state.$view - * - * @description - * - * @param {string} name name - * @param {object} options option object. - */ - load: function load(name, options) { - var result, defaults = { - template: null, controller: null, view: null, locals: null, notify: true, async: true, params: {} - }; - options = extend(defaults, options); - - if (options.view) { - result = $templateFactory.fromConfig(options.view, options.params, options.locals); - } - if (result && options.notify) { - /** - * @ngdoc event - * @name ui.router.state.$state#$viewContentLoading - * @eventOf ui.router.state.$view - * @eventType broadcast on root scope - * @description - * - * Fired once the view **begins loading**, *before* the DOM is rendered. - * - * @param {Object} event Event object. - * @param {Object} viewConfig The view config properties (template, controller, etc). - * - * @example - * - *
-         * $scope.$on('$viewContentLoading',
-         * function(event, viewConfig){
-         *     // Access to all the view config properties.
-         *     // and one special property 'targetView'
-         *     // viewConfig.targetView
-         * });
-         * 
- */ - $rootScope.$broadcast('$viewContentLoading', options); - } - return result; - } - }; - } -} - -angular.module('ui.router.state').provider('$view', $ViewProvider); - -/** - * @ngdoc object - * @name ui.router.state.$uiViewScrollProvider - * - * @description - * Provider that returns the {@link ui.router.state.$uiViewScroll} service function. - */ -function $ViewScrollProvider() { - - var useAnchorScroll = false; - - /** - * @ngdoc function - * @name ui.router.state.$uiViewScrollProvider#useAnchorScroll - * @methodOf ui.router.state.$uiViewScrollProvider - * - * @description - * Reverts back to using the core [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) service for - * scrolling based on the url anchor. - */ - this.useAnchorScroll = function () { - useAnchorScroll = true; - }; - - /** - * @ngdoc object - * @name ui.router.state.$uiViewScroll - * - * @requires $anchorScroll - * @requires $timeout - * - * @description - * When called with a jqLite element, it scrolls the element into view (after a - * `$timeout` so the DOM has time to refresh). - * - * If you prefer to rely on `$anchorScroll` to scroll the view to the anchor, - * this can be enabled by calling {@link ui.router.state.$uiViewScrollProvider#methods_useAnchorScroll `$uiViewScrollProvider.useAnchorScroll()`}. - */ - this.$get = ['$anchorScroll', '$timeout', function ($anchorScroll, $timeout) { - if (useAnchorScroll) { - return $anchorScroll; - } - - return function ($element) { - $timeout(function () { - $element[0].scrollIntoView(); - }, 0, false); - }; - }]; -} - -angular.module('ui.router.state').provider('$uiViewScroll', $ViewScrollProvider); - -/** - * @ngdoc directive - * @name ui.router.state.directive:ui-view - * - * @requires ui.router.state.$state - * @requires $compile - * @requires $controller - * @requires $injector - * @requires ui.router.state.$uiViewScroll - * @requires $document - * - * @restrict ECA - * - * @description - * The ui-view directive tells $state where to place your templates. - * - * @param {string=} name A view name. The name should be unique amongst the other views in the - * same state. You can have views of the same name that live in different states. - * - * @param {string=} autoscroll It allows you to set the scroll behavior of the browser window - * when a view is populated. By default, $anchorScroll is overridden by ui-router's custom scroll - * service, {@link ui.router.state.$uiViewScroll}. This custom service let's you - * scroll ui-view elements into view when they are populated during a state activation. - * - * *Note: To revert back to old [`$anchorScroll`](http://docs.angularjs.org/api/ng.$anchorScroll) - * functionality, call `$uiViewScrollProvider.useAnchorScroll()`.* - * - * @param {string=} onload Expression to evaluate whenever the view updates. - * - * @example - * A view can be unnamed or named. - *
- * 
- * 
- * - * - *
- *
- * - * You can only have one unnamed view within any template (or root html). If you are only using a - * single view and it is unnamed then you can populate it like so: - *
- * 
- * $stateProvider.state("home", { - * template: "

HELLO!

" - * }) - *
- * - * The above is a convenient shortcut equivalent to specifying your view explicitly with the {@link ui.router.state.$stateProvider#views `views`} - * config property, by name, in this case an empty name: - *
- * $stateProvider.state("home", {
- *   views: {
- *     "": {
- *       template: "

HELLO!

" - * } - * } - * }) - *
- * - * But typically you'll only use the views property if you name your view or have more than one view - * in the same template. There's not really a compelling reason to name a view if its the only one, - * but you could if you wanted, like so: - *
- * 
- *
- *
- * $stateProvider.state("home", {
- *   views: {
- *     "main": {
- *       template: "

HELLO!

" - * } - * } - * }) - *
- * - * Really though, you'll use views to set up multiple views: - *
- * 
- *
- *
- *
- * - *
- * $stateProvider.state("home", {
- *   views: {
- *     "": {
- *       template: "

HELLO!

" - * }, - * "chart": { - * template: "" - * }, - * "data": { - * template: "" - * } - * } - * }) - *
- * - * Examples for `autoscroll`: - * - *
- * 
- * 
- *
- * 
- * 
- * 
- * 
- * 
- */ -$ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll', '$interpolate']; -function $ViewDirective( $state, $injector, $uiViewScroll, $interpolate) { - - function getService() { - return ($injector.has) ? function(service) { - return $injector.has(service) ? $injector.get(service) : null; - } : function(service) { - try { - return $injector.get(service); - } catch (e) { - return null; - } - }; - } - - var service = getService(), - $animator = service('$animator'), - $animate = service('$animate'); - - // Returns a set of DOM manipulation functions based on which Angular version - // it should use - function getRenderer(attrs, scope) { - var statics = function() { - return { - enter: function (element, target, cb) { target.after(element); cb(); }, - leave: function (element, cb) { element.remove(); cb(); } - }; - }; - - if ($animate) { - return { - enter: function(element, target, cb) { - var promise = $animate.enter(element, null, target, cb); - if (promise && promise.then) promise.then(cb); - }, - leave: function(element, cb) { - var promise = $animate.leave(element, cb); - if (promise && promise.then) promise.then(cb); - } - }; - } - - if ($animator) { - var animate = $animator && $animator(scope, attrs); - - return { - enter: function(element, target, cb) {animate.enter(element, null, target); cb(); }, - leave: function(element, cb) { animate.leave(element); cb(); } - }; - } - - return statics(); - } - - var directive = { - restrict: 'ECA', - terminal: true, - priority: 400, - transclude: 'element', - compile: function (tElement, tAttrs, $transclude) { - return function (scope, $element, attrs) { - var previousEl, currentEl, currentScope, latestLocals, - onloadExp = attrs.onload || '', - autoScrollExp = attrs.autoscroll, - renderer = getRenderer(attrs, scope); - - scope.$on('$stateChangeSuccess', function() { - updateView(false); - }); - scope.$on('$viewContentLoading', function() { - updateView(false); - }); - - updateView(true); - - function cleanupLastView() { - if (previousEl) { - previousEl.remove(); - previousEl = null; - } - - if (currentScope) { - currentScope.$destroy(); - currentScope = null; - } - - if (currentEl) { - renderer.leave(currentEl, function() { - previousEl = null; - }); - - previousEl = currentEl; - currentEl = null; - } - } - - function updateView(firstTime) { - var newScope, - name = getUiViewName(scope, attrs, $element, $interpolate), - previousLocals = name && $state.$current && $state.$current.locals[name]; - - if (!firstTime && previousLocals === latestLocals) return; // nothing to do - newScope = scope.$new(); - latestLocals = $state.$current.locals[name]; - - var clone = $transclude(newScope, function(clone) { - renderer.enter(clone, $element, function onUiViewEnter() { - if(currentScope) { - currentScope.$emit('$viewContentAnimationEnded'); - } - - if (angular.isDefined(autoScrollExp) && !autoScrollExp || scope.$eval(autoScrollExp)) { - $uiViewScroll(clone); - } - }); - cleanupLastView(); - }); - - currentEl = clone; - currentScope = newScope; - /** - * @ngdoc event - * @name ui.router.state.directive:ui-view#$viewContentLoaded - * @eventOf ui.router.state.directive:ui-view - * @eventType emits on ui-view directive scope - * @description * - * Fired once the view is **loaded**, *after* the DOM is rendered. - * - * @param {Object} event Event object. - */ - currentScope.$emit('$viewContentLoaded'); - currentScope.$eval(onloadExp); - } - }; - } - }; - - return directive; -} - -$ViewDirectiveFill.$inject = ['$compile', '$controller', '$state', '$interpolate']; -function $ViewDirectiveFill ( $compile, $controller, $state, $interpolate) { - return { - restrict: 'ECA', - priority: -400, - compile: function (tElement) { - var initial = tElement.html(); - return function (scope, $element, attrs) { - var current = $state.$current, - name = getUiViewName(scope, attrs, $element, $interpolate), - locals = current && current.locals[name]; - - if (! locals) { - return; - } - - $element.data('$uiView', { name: name, state: locals.$$state }); - $element.html(locals.$template ? locals.$template : initial); - - var link = $compile($element.contents()); - - if (locals.$$controller) { - locals.$scope = scope; - var controller = $controller(locals.$$controller, locals); - if (locals.$$controllerAs) { - scope[locals.$$controllerAs] = controller; - } - $element.data('$ngControllerController', controller); - $element.children().data('$ngControllerController', controller); - } - - link(scope); - }; - } - }; -} - -/** - * Shared ui-view code for both directives: - * Given scope, element, and its attributes, return the view's name - */ -function getUiViewName(scope, attrs, element, $interpolate) { - var name = $interpolate(attrs.uiView || attrs.name || '')(scope); - var inherited = element.inheritedData('$uiView'); - return name.indexOf('@') >= 0 ? name : (name + '@' + (inherited ? inherited.state.name : '')); -} - -angular.module('ui.router.state').directive('uiView', $ViewDirective); -angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill); - -function parseStateRef(ref, current) { - var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed; - if (preparsed) ref = current + '(' + preparsed[1] + ')'; - parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/); - if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'"); - return { state: parsed[1], paramExpr: parsed[3] || null }; -} - -function stateContext(el) { - var stateData = el.parent().inheritedData('$uiView'); - - if (stateData && stateData.state && stateData.state.name) { - return stateData.state; - } -} - -/** - * @ngdoc directive - * @name ui.router.state.directive:ui-sref - * - * @requires ui.router.state.$state - * @requires $timeout - * - * @restrict A - * - * @description - * A directive that binds a link (`` tag) to a state. If the state has an associated - * URL, the directive will automatically generate & update the `href` attribute via - * the {@link ui.router.state.$state#methods_href $state.href()} method. Clicking - * the link will trigger a state transition with optional parameters. - * - * Also middle-clicking, right-clicking, and ctrl-clicking on the link will be - * handled natively by the browser. - * - * You can also use relative state paths within ui-sref, just like the relative - * paths passed to `$state.go()`. You just need to be aware that the path is relative - * to the state that the link lives in, in other words the state that loaded the - * template containing the link. - * - * You can specify options to pass to {@link ui.router.state.$state#go $state.go()} - * using the `ui-sref-opts` attribute. Options are restricted to `location`, `inherit`, - * and `reload`. - * - * @example - * Here's an example of how you'd use ui-sref and how it would compile. If you have the - * following template: - *
- * Home | About | Next page
- * 
- * 
- * 
- * - * Then the compiled html would be (assuming Html5Mode is off and current state is contacts): - *
- * Home | About | Next page
- * 
- * 
    - *
  • - * Joe - *
  • - *
  • - * Alice - *
  • - *
  • - * Bob - *
  • - *
- * - * Home - *
- * - * @param {string} ui-sref 'stateName' can be any valid absolute or relative state - * @param {Object} ui-sref-opts options to pass to {@link ui.router.state.$state#go $state.go()} - */ -$StateRefDirective.$inject = ['$state', '$timeout']; -function $StateRefDirective($state, $timeout) { - var allowedOptions = ['location', 'inherit', 'reload']; - - return { - restrict: 'A', - require: ['?^uiSrefActive', '?^uiSrefActiveEq'], - link: function(scope, element, attrs, uiSrefActive) { - var ref = parseStateRef(attrs.uiSref, $state.current.name); - var params = null, url = null, base = stateContext(element) || $state.$current; - var newHref = null, isAnchor = element.prop("tagName") === "A"; - var isForm = element[0].nodeName === "FORM"; - var attr = isForm ? "action" : "href", nav = true; - - var options = { relative: base, inherit: true }; - var optionsOverride = scope.$eval(attrs.uiSrefOpts) || {}; - - angular.forEach(allowedOptions, function(option) { - if (option in optionsOverride) { - options[option] = optionsOverride[option]; - } - }); - - var update = function(newVal) { - if (newVal) params = angular.copy(newVal); - if (!nav) return; - - newHref = $state.href(ref.state, params, options); - - var activeDirective = uiSrefActive[1] || uiSrefActive[0]; - if (activeDirective) { - activeDirective.$$setStateInfo(ref.state, params); - } - if (newHref === null) { - nav = false; - return false; - } - attrs.$set(attr, newHref); - }; - - if (ref.paramExpr) { - scope.$watch(ref.paramExpr, function(newVal, oldVal) { - if (newVal !== params) update(newVal); - }, true); - params = angular.copy(scope.$eval(ref.paramExpr)); - } - update(); - - if (isForm) return; - - element.bind("click", function(e) { - var button = e.which || e.button; - if ( !(button > 1 || e.ctrlKey || e.metaKey || e.shiftKey || element.attr('target')) ) { - // HACK: This is to allow ng-clicks to be processed before the transition is initiated: - var transition = $timeout(function() { - $state.go(ref.state, params, options); - }); - e.preventDefault(); - - // if the state has no URL, ignore one preventDefault from the directive. - var ignorePreventDefaultCount = isAnchor && !newHref ? 1: 0; - e.preventDefault = function() { - if (ignorePreventDefaultCount-- <= 0) - $timeout.cancel(transition); - }; - } - }); - } - }; -} - -/** - * @ngdoc directive - * @name ui.router.state.directive:ui-sref-active - * - * @requires ui.router.state.$state - * @requires ui.router.state.$stateParams - * @requires $interpolate - * - * @restrict A - * - * @description - * A directive working alongside ui-sref to add classes to an element when the - * related ui-sref directive's state is active, and removing them when it is inactive. - * The primary use-case is to simplify the special appearance of navigation menus - * relying on `ui-sref`, by having the "active" state's menu button appear different, - * distinguishing it from the inactive menu items. - * - * ui-sref-active can live on the same element as ui-sref or on a parent element. The first - * ui-sref-active found at the same level or above the ui-sref will be used. - * - * Will activate when the ui-sref's target state or any child state is active. If you - * need to activate only when the ui-sref target state is active and *not* any of - * it's children, then you will use - * {@link ui.router.state.directive:ui-sref-active-eq ui-sref-active-eq} - * - * @example - * Given the following template: - *
- * 
- * 
- * - * - * When the app state is "app.user" (or any children states), and contains the state parameter "user" with value "bilbobaggins", - * the resulting HTML will appear as (note the 'active' class): - *
- * 
- * 
- * - * The class name is interpolated **once** during the directives link time (any further changes to the - * interpolated value are ignored). - * - * Multiple classes may be specified in a space-separated format: - *
- * 
    - *
  • - * link - *
  • - *
- *
- */ - -/** - * @ngdoc directive - * @name ui.router.state.directive:ui-sref-active-eq - * - * @requires ui.router.state.$state - * @requires ui.router.state.$stateParams - * @requires $interpolate - * - * @restrict A - * - * @description - * The same as {@link ui.router.state.directive:ui-sref-active ui-sref-active} but will only activate - * when the exact target state used in the `ui-sref` is active; no child states. - * - */ -$StateRefActiveDirective.$inject = ['$state', '$stateParams', '$interpolate']; -function $StateRefActiveDirective($state, $stateParams, $interpolate) { - return { - restrict: "A", - controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) { - var state, params, activeClass; - - // There probably isn't much point in $observing this - // uiSrefActive and uiSrefActiveEq share the same directive object with some - // slight difference in logic routing - activeClass = $interpolate($attrs.uiSrefActiveEq || $attrs.uiSrefActive || '', false)($scope); - - // Allow uiSref to communicate with uiSrefActive[Equals] - this.$$setStateInfo = function (newState, newParams) { - state = $state.get(newState, stateContext($element)); - params = newParams; - update(); - }; - - $scope.$on('$stateChangeSuccess', update); - - // Update route state - function update() { - if (isMatch()) { - $element.addClass(activeClass); - } else { - $element.removeClass(activeClass); - } - } - - function isMatch() { - if (typeof $attrs.uiSrefActiveEq !== 'undefined') { - return state && $state.is(state.name, params); - } else { - return state && $state.includes(state.name, params); - } - } - }] - }; -} - -angular.module('ui.router.state') - .directive('uiSref', $StateRefDirective) - .directive('uiSrefActive', $StateRefActiveDirective) - .directive('uiSrefActiveEq', $StateRefActiveDirective); - -/** - * @ngdoc filter - * @name ui.router.state.filter:isState - * - * @requires ui.router.state.$state - * - * @description - * Translates to {@link ui.router.state.$state#methods_is $state.is("stateName")}. - */ -$IsStateFilter.$inject = ['$state']; -function $IsStateFilter($state) { - var isFilter = function (state) { - return $state.is(state); - }; - isFilter.$stateful = true; - return isFilter; -} - -/** - * @ngdoc filter - * @name ui.router.state.filter:includedByState - * - * @requires ui.router.state.$state - * - * @description - * Translates to {@link ui.router.state.$state#methods_includes $state.includes('fullOrPartialStateName')}. - */ -$IncludedByStateFilter.$inject = ['$state']; -function $IncludedByStateFilter($state) { - var includesFilter = function (state) { - return $state.includes(state); - }; - includesFilter.$stateful = true; - return includesFilter; -} - -angular.module('ui.router.state') - .filter('isState', $IsStateFilter) - .filter('includedByState', $IncludedByStateFilter); -})(window, window.angular); -/* angular-moment.js / v0.10.1 / (c) 2013, 2014, 2015 Uri Shaked / MIT Licence */ - -'format amd'; -/* global define */ - -(function () { - 'use strict'; - - function angularMoment(angular, moment) { - - /** - * @ngdoc overview - * @name angularMoment - * - * @description - * angularMoment module provides moment.js functionality for angular.js apps. - */ - return angular.module('angularMoment', []) - - /** - * @ngdoc object - * @name angularMoment.config:angularMomentConfig - * - * @description - * Common configuration of the angularMoment module - */ - .constant('angularMomentConfig', { - /** - * @ngdoc property - * @name angularMoment.config.angularMomentConfig#preprocess - * @propertyOf angularMoment.config:angularMomentConfig - * @returns {string} The default preprocessor to apply - * - * @description - * Defines a default preprocessor to apply (e.g. 'unix', 'etc', ...). The default value is null, - * i.e. no preprocessor will be applied. - */ - preprocess: null, // e.g. 'unix', 'utc', ... - - /** - * @ngdoc property - * @name angularMoment.config.angularMomentConfig#timezone - * @propertyOf angularMoment.config:angularMomentConfig - * @returns {string} The default timezone - * - * @description - * The default timezone (e.g. 'Europe/London'). Empty string by default (does not apply - * any timezone shift). - */ - timezone: '', - - /** - * @ngdoc property - * @name angularMoment.config.angularMomentConfig#format - * @propertyOf angularMoment.config:angularMomentConfig - * @returns {string} The pre-conversion format of the date - * - * @description - * Specify the format of the input date. Essentially it's a - * default and saves you from specifying a format in every - * element. Overridden by element attr. Null by default. - */ - format: null, - - /** - * @ngdoc property - * @name angularMoment.config.angularMomentConfig#statefulFilters - * @propertyOf angularMoment.config:angularMomentConfig - * @returns {boolean} Whether angular-moment filters should be stateless (or not) - * - * @description - * Specifies whether the filters included with angular-moment are stateful. - * Stateful filters will automatically re-evaluate whenever you change the timezone - * or language settings, but may negatively impact performance. true by default. - */ - statefulFilters: true - }) - - /** - * @ngdoc object - * @name angularMoment.object:moment - * - * @description - * moment global (as provided by the moment.js library) - */ - .constant('moment', moment) - - /** - * @ngdoc object - * @name angularMoment.config:amTimeAgoConfig - * @module angularMoment - * - * @description - * configuration specific to the amTimeAgo directive - */ - .constant('amTimeAgoConfig', { - /** - * @ngdoc property - * @name angularMoment.config.amTimeAgoConfig#withoutSuffix - * @propertyOf angularMoment.config:amTimeAgoConfig - * @returns {boolean} Whether to include a suffix in am-time-ago directive - * - * @description - * Defaults to false. - */ - withoutSuffix: false, - - /** - * @ngdoc property - * @name angularMoment.config.amTimeAgoConfig#serverTime - * @propertyOf angularMoment.config:amTimeAgoConfig - * @returns {number} Server time in milliseconds since the epoch - * - * @description - * If set, time ago will be calculated relative to the given value. - * If null, local time will be used. Defaults to null. - */ - serverTime: null, - - /** - * @ngdoc property - * @name angularMoment.config.amTimeAgoConfig#titleFormat - * @propertyOf angularMoment.config:amTimeAgoConfig - * @returns {string} The format of the date to be displayed in the title of the element. If null, - * the directive set the title of the element. - * - * @description - * The format of the date used for the title of the element. null by default. - */ - titleFormat: null, - - /** - * @ngdoc property - * @name angularMoment.config.amTimeAgoConfig#fullDateThreshold - * @propertyOf angularMoment.config:amTimeAgoConfig - * @returns {number} The minimum number of days for showing a full date instead of relative time - * - * @description - * The threshold for displaying a full date. The default is null, which means the date will always - * be relative, and full date will never be displayed. - */ - fullDateThreshold: null, - - /** - * @ngdoc property - * @name angularMoment.config.amTimeAgoConfig#fullDateFormat - * @propertyOf angularMoment.config:amTimeAgoConfig - * @returns {string} The format to use when displaying a full date. - * - * @description - * Specify the format of the date when displayed as full date. null by default. - */ - fullDateFormat: null - }) - - /** - * @ngdoc directive - * @name angularMoment.directive:amTimeAgo - * @module angularMoment - * - * @restrict A - */ - .directive('amTimeAgo', ['$window', 'moment', 'amMoment', 'amTimeAgoConfig', 'angularMomentConfig', function ($window, moment, amMoment, amTimeAgoConfig, angularMomentConfig) { - - return function (scope, element, attr) { - var activeTimeout = null; - var currentValue; - var currentFormat = angularMomentConfig.format; - var withoutSuffix = amTimeAgoConfig.withoutSuffix; - var titleFormat = amTimeAgoConfig.titleFormat; - var fullDateThreshold = amTimeAgoConfig.fullDateThreshold; - var fullDateFormat = amTimeAgoConfig.fullDateFormat; - var localDate = new Date().getTime(); - var preprocess = angularMomentConfig.preprocess; - var modelName = attr.amTimeAgo; - var isTimeElement = ('TIME' === element[0].nodeName.toUpperCase()); - - function getNow() { - var now; - if (amTimeAgoConfig.serverTime) { - var localNow = new Date().getTime(); - var nowMillis = localNow - localDate + amTimeAgoConfig.serverTime; - now = moment(nowMillis); - } - else { - now = moment(); - } - return now; - } - - function cancelTimer() { - if (activeTimeout) { - $window.clearTimeout(activeTimeout); - activeTimeout = null; - } - } - - function updateTime(momentInstance) { - var daysAgo = getNow().diff(momentInstance, 'day'); - var showFullDate = fullDateThreshold && daysAgo >= fullDateThreshold; - - if (showFullDate) { - element.text(momentInstance.format(fullDateFormat)); - } else { - element.text(momentInstance.from(getNow(), withoutSuffix)); - } - - if (titleFormat && !element.attr('title')) { - element.attr('title', momentInstance.local().format(titleFormat)); - } - - if (!showFullDate) { - var howOld = Math.abs(getNow().diff(momentInstance, 'minute')); - var secondsUntilUpdate = 3600; - if (howOld < 1) { - secondsUntilUpdate = 1; - } else if (howOld < 60) { - secondsUntilUpdate = 30; - } else if (howOld < 180) { - secondsUntilUpdate = 300; - } - - activeTimeout = $window.setTimeout(function () { - updateTime(momentInstance); - }, secondsUntilUpdate * 1000); - } - } - - function updateDateTimeAttr(value) { - if (isTimeElement) { - element.attr('datetime', value); - } - } - - function updateMoment() { - cancelTimer(); - if (currentValue) { - var momentValue = amMoment.preprocessDate(currentValue, preprocess, currentFormat); - updateTime(momentValue); - updateDateTimeAttr(momentValue.toISOString()); - } - } - - scope.$watch(modelName, function (value) { - if ((typeof value === 'undefined') || (value === null) || (value === '')) { - cancelTimer(); - if (currentValue) { - element.text(''); - updateDateTimeAttr(''); - currentValue = null; - } - return; - } - - currentValue = value; - updateMoment(); - }); - - if (angular.isDefined(attr.amWithoutSuffix)) { - scope.$watch(attr.amWithoutSuffix, function (value) { - if (typeof value === 'boolean') { - withoutSuffix = value; - updateMoment(); - } else { - withoutSuffix = amTimeAgoConfig.withoutSuffix; - } - }); - } - - attr.$observe('amFormat', function (format) { - if (typeof format !== 'undefined') { - currentFormat = format; - updateMoment(); - } - }); - - attr.$observe('amPreprocess', function (newValue) { - preprocess = newValue; - updateMoment(); - }); - - attr.$observe('amFullDateThreshold', function (newValue) { - fullDateThreshold = newValue; - updateMoment(); - }); - - attr.$observe('amFullDateFormat', function (newValue) { - fullDateFormat = newValue; - updateMoment(); - }); - - scope.$on('$destroy', function () { - cancelTimer(); - }); - - scope.$on('amMoment:localeChanged', function () { - updateMoment(); - }); - }; - }]) - - /** - * @ngdoc service - * @name angularMoment.service.amMoment - * @module angularMoment - */ - .service('amMoment', ['moment', '$rootScope', '$log', 'angularMomentConfig', function (moment, $rootScope, $log, angularMomentConfig) { - /** - * @ngdoc property - * @name angularMoment:amMoment#preprocessors - * @module angularMoment - * - * @description - * Defines the preprocessors for the preprocessDate method. By default, the following preprocessors - * are defined: utc, unix. - */ - this.preprocessors = { - utc: moment.utc, - unix: moment.unix - }; - - /** - * @ngdoc function - * @name angularMoment.service.amMoment#changeLocale - * @methodOf angularMoment.service.amMoment - * - * @description - * Changes the locale for moment.js and updates all the am-time-ago directive instances - * with the new locale. Also broadcasts an `amMoment:localeChanged` event on $rootScope. - * - * @param {string} locale Locale code (e.g. en, es, ru, pt-br, etc.) - * @param {object} customization object of locale strings to override - */ - this.changeLocale = function (locale, customization) { - var result = moment.locale(locale, customization); - if (angular.isDefined(locale)) { - $rootScope.$broadcast('amMoment:localeChanged'); - - } - return result; - }; - - /** - * @ngdoc function - * @name angularMoment.service.amMoment#changeTimezone - * @methodOf angularMoment.service.amMoment - * - * @description - * Changes the default timezone for amCalendar, amDateFormat and amTimeAgo. Also broadcasts an - * `amMoment:timezoneChanged` event on $rootScope. - * - * @param {string} timezone Timezone name (e.g. UTC) - */ - this.changeTimezone = function (timezone) { - angularMomentConfig.timezone = timezone; - $rootScope.$broadcast('amMoment:timezoneChanged'); - }; - - /** - * @ngdoc function - * @name angularMoment.service.amMoment#preprocessDate - * @methodOf angularMoment.service.amMoment - * - * @description - * Preprocess a given value and convert it into a Moment instance appropriate for use in the - * am-time-ago directive and the filters. - * - * @param {*} value The value to be preprocessed - * @param {string} preprocess The name of the preprocessor the apply (e.g. utc, unix) - * @param {string=} format Specifies how to parse the value (see {@link http://momentjs.com/docs/#/parsing/string-format/}) - * @return {Moment} A value that can be parsed by the moment library - */ - this.preprocessDate = function (value, preprocess, format) { - if (angular.isUndefined(preprocess)) { - preprocess = angularMomentConfig.preprocess; - } - if (this.preprocessors[preprocess]) { - return this.preprocessors[preprocess](value, format); - } - if (preprocess) { - $log.warn('angular-moment: Ignoring unsupported value for preprocess: ' + preprocess); - } - if (!isNaN(parseFloat(value)) && isFinite(value)) { - // Milliseconds since the epoch - return moment(parseInt(value, 10)); - } - // else just returns the value as-is. - return moment(value, format); - }; - - /** - * @ngdoc function - * @name angularMoment.service.amMoment#applyTimezone - * @methodOf angularMoment.service.amMoment - * - * @description - * Apply a timezone onto a given moment object - if moment-timezone.js is included - * Otherwise, it'll not apply any timezone shift. - * - * @param {Moment} aMoment a moment() instance to apply the timezone shift to - * @param {string=} timezone The timezone to apply. If none given, will apply the timezone - * configured in angularMomentConfig.timezone. - * - * @returns {Moment} The given moment with the timezone shift applied - */ - this.applyTimezone = function (aMoment, timezone) { - timezone = timezone || angularMomentConfig.timezone; - if (aMoment && timezone) { - if (aMoment.tz) { - aMoment = aMoment.tz(timezone); - } else { - $log.warn('angular-moment: timezone specified but moment.tz() is undefined. Did you forget to include moment-timezone.js?'); - } - } - return aMoment; - }; - }]) - - /** - * @ngdoc filter - * @name angularMoment.filter:amCalendar - * @module angularMoment - */ - .filter('amCalendar', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) { - function amCalendarFilter(value, preprocess) { - if (typeof value === 'undefined' || value === null) { - return ''; - } - - value = amMoment.preprocessDate(value, preprocess); - var date = moment(value); - if (!date.isValid()) { - return ''; - } - - return amMoment.applyTimezone(date).calendar(); - } - - // Since AngularJS 1.3, filters have to explicitly define being stateful - // (this is no longer the default). - amCalendarFilter.$stateful = angularMomentConfig.statefulFilters; - - return amCalendarFilter; - }]) - - /** - * @ngdoc filter - * @name angularMoment.filter:amDifference - * @module angularMoment - */ - .filter('amDifference', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) { - function amDifferenceFilter(value, otherValue, unit, usePrecision, preprocessValue, preprocessOtherValue) { - if (typeof value === 'undefined' || value === null) { - return ''; - } - - value = amMoment.preprocessDate(value, preprocessValue); - var date = moment(value); - if (!date.isValid()) { - return ''; - } - - var date2; - if (typeof otherValue === 'undefined' || otherValue === null) { - date2 = moment(); - } else { - otherValue = amMoment.preprocessDate(otherValue, preprocessOtherValue); - date2 = moment(otherValue); - if (!date2.isValid()) { - return ''; - } - } - - return amMoment.applyTimezone(date).diff(amMoment.applyTimezone(date2), unit, usePrecision); - } - - amDifferenceFilter.$stateful = angularMomentConfig.statefulFilters; - - return amDifferenceFilter; - }]) - - /** - * @ngdoc filter - * @name angularMoment.filter:amDateFormat - * @module angularMoment - * @function - */ - .filter('amDateFormat', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) { - function amDateFormatFilter(value, format, preprocess, timezone) { - if (typeof value === 'undefined' || value === null) { - return ''; - } - - value = amMoment.preprocessDate(value, preprocess); - var date = moment(value); - if (!date.isValid()) { - return ''; - } - - return amMoment.applyTimezone(date, timezone).format(format); - } - - amDateFormatFilter.$stateful = angularMomentConfig.statefulFilters; - - return amDateFormatFilter; - }]) - - /** - * @ngdoc filter - * @name angularMoment.filter:amDurationFormat - * @module angularMoment - * @function - */ - .filter('amDurationFormat', ['moment', 'angularMomentConfig', function (moment, angularMomentConfig) { - function amDurationFormatFilter(value, format, suffix) { - if (typeof value === 'undefined' || value === null) { - return ''; - } - - return moment.duration(value, format).humanize(suffix); - } - - amDurationFormatFilter.$stateful = angularMomentConfig.statefulFilters; - - return amDurationFormatFilter; - }]) - - /** - * @ngdoc filter - * @name angularMoment.filter:amTimeAgo - * @module angularMoment - * @function - */ - .filter('amTimeAgo', ['moment', 'amMoment', 'angularMomentConfig', function (moment, amMoment, angularMomentConfig) { - function amTimeAgoFilter(value, preprocess, suffix) { - if (typeof value === 'undefined' || value === null) { - return ''; - } - - value = amMoment.preprocessDate(value, preprocess); - var date = moment(value); - if (!date.isValid()) { - return ''; - } - - return amMoment.applyTimezone(date).fromNow(suffix); - } - - amTimeAgoFilter.$stateful = angularMomentConfig.statefulFilters; - - return amTimeAgoFilter; - }]); - } - - if (typeof define === 'function' && define.amd) { - define(['angular', 'moment'], angularMoment); - } else if (typeof module !== 'undefined' && module && module.exports) { - angularMoment(angular, require('moment')); - module.exports = 'angularMoment'; - } else { - angularMoment(angular, window.moment); - } -})(); - -/** - * @license - * lodash 3.8.0 (Custom Build) - * Build: `lodash modern exports="amd,commonjs,node" iife="angular.module('ngLodash', []).constant('lodash', null).config(function ($provide) { %output% $provide.constant('lodash', _);});" --output build/ng-lodash.js` - * Copyright 2012-2015 The Dojo Foundation - * Based on Underscore.js 1.8.3 - * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * Available under MIT license - */ -angular.module('ngLodash', []).constant('lodash', null).config([ - '$provide', - function ($provide) { - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - /** Used as the semantic version number. */ - var VERSION = '3.8.0'; - /** Used to compose bitmasks for wrapper metadata. */ - var BIND_FLAG = 1, BIND_KEY_FLAG = 2, CURRY_BOUND_FLAG = 4, CURRY_FLAG = 8, CURRY_RIGHT_FLAG = 16, PARTIAL_FLAG = 32, PARTIAL_RIGHT_FLAG = 64, ARY_FLAG = 128, REARG_FLAG = 256; - /** Used as default options for `_.trunc`. */ - var DEFAULT_TRUNC_LENGTH = 30, DEFAULT_TRUNC_OMISSION = '...'; - /** Used to detect when a function becomes hot. */ - var HOT_COUNT = 150, HOT_SPAN = 16; - /** Used to indicate the type of lazy iteratees. */ - var LAZY_DROP_WHILE_FLAG = 0, LAZY_FILTER_FLAG = 1, LAZY_MAP_FLAG = 2; - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', weakMapTag = '[object WeakMap]'; - var arrayBufferTag = '[object ArrayBuffer]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, reUnescapedHtml = /[&<>"'`]/g, reHasEscapedHtml = RegExp(reEscapedHtml.source), reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, reEvaluate = /<%([\s\S]+?)%>/g, reInterpolate = /<%=([\s\S]+?)%>/g; - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; - /** - * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special). - * In addition to special characters the forward slash is escaped to allow for - * easier `eval` use and `Function` compilation. - */ - var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, reHasRegExpChars = RegExp(reRegExpChars.source); - /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */ - var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g; - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - /** Used to match [ES template delimiters](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-template-literal-lexical-components). */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - /** Used to detect hexadecimal string values. */ - var reHasHexPrefix = /^0[xX]/; - /** Used to detect host constructors (Safari > 5). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ - var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - /** Used to match words to create compound words. */ - var reWords = function () { - var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; - return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g'); - }(); - /** Used to detect and test for whitespace. */ - var whitespace = ' \t\x0B\f\xa0\ufeff' + '\n\r\u2028\u2029' + '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'; - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', - 'ArrayBuffer', - 'Date', - 'Error', - 'Float32Array', - 'Float64Array', - 'Function', - 'Int8Array', - 'Int16Array', - 'Int32Array', - 'Math', - 'Number', - 'Object', - 'RegExp', - 'Set', - 'String', - '_', - 'clearTimeout', - 'document', - 'isFinite', - 'parseInt', - 'setTimeout', - 'TypeError', - 'Uint8Array', - 'Uint8ClampedArray', - 'Uint16Array', - 'Uint32Array', - 'WeakMap', - 'window' - ]; - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[stringTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[mapTag] = cloneableTags[setTag] = cloneableTags[weakMapTag] = false; - /** Used as an internal `_.debounce` options object by `_.throttle`. */ - var debounceOptions = { - 'leading': false, - 'maxWait': 0, - 'trailing': false - }; - /** Used to map latin-1 supplementary letters to basic latin letters. */ - var deburredLetters = { - '\xc0': 'A', - '\xc1': 'A', - '\xc2': 'A', - '\xc3': 'A', - '\xc4': 'A', - '\xc5': 'A', - '\xe0': 'a', - '\xe1': 'a', - '\xe2': 'a', - '\xe3': 'a', - '\xe4': 'a', - '\xe5': 'a', - '\xc7': 'C', - '\xe7': 'c', - '\xd0': 'D', - '\xf0': 'd', - '\xc8': 'E', - '\xc9': 'E', - '\xca': 'E', - '\xcb': 'E', - '\xe8': 'e', - '\xe9': 'e', - '\xea': 'e', - '\xeb': 'e', - '\xcc': 'I', - '\xcd': 'I', - '\xce': 'I', - '\xcf': 'I', - '\xec': 'i', - '\xed': 'i', - '\xee': 'i', - '\xef': 'i', - '\xd1': 'N', - '\xf1': 'n', - '\xd2': 'O', - '\xd3': 'O', - '\xd4': 'O', - '\xd5': 'O', - '\xd6': 'O', - '\xd8': 'O', - '\xf2': 'o', - '\xf3': 'o', - '\xf4': 'o', - '\xf5': 'o', - '\xf6': 'o', - '\xf8': 'o', - '\xd9': 'U', - '\xda': 'U', - '\xdb': 'U', - '\xdc': 'U', - '\xf9': 'u', - '\xfa': 'u', - '\xfb': 'u', - '\xfc': 'u', - '\xdd': 'Y', - '\xfd': 'y', - '\xff': 'y', - '\xc6': 'Ae', - '\xe6': 'ae', - '\xde': 'Th', - '\xfe': 'th', - '\xdf': 'ss' - }; - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''', - '`': '`' - }; - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': '\'', - '`': '`' - }; - /** Used to determine if values are of the language type `Object`. */ - var objectTypes = { - 'function': true, - 'object': true - }; - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - '\'': '\'', - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - /** Detect free variable `exports`. */ - var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; - /** Detect free variable `module`. */ - var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; - /** Detect free variable `global` from Node.js. */ - var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; - /** Detect free variable `self`. */ - var freeSelf = objectTypes[typeof self] && self && self.Object && self; - /** Detect free variable `window`. */ - var freeWindow = objectTypes[typeof window] && window && window.Object && window; - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; - /** - * Used as a reference to the global object. - * - * The `this` value is used if it is the global object to avoid Greasemonkey's - * restricted `window` object, otherwise the `window` object is used. - */ - var root = freeGlobal || freeWindow !== (this && this.window) && freeWindow || freeSelf || this; - /** - * The base implementation of `compareAscending` which compares values and - * sorts them in ascending order without guaranteeing a stable sort. - * - * @private - * @param {*} value The value to compare to `other`. - * @param {*} other The value to compare to `value`. - * @returns {number} Returns the sort order indicator for `value`. - */ - function baseCompareAscending(value, other) { - if (value !== other) { - var valIsReflexive = value === value, othIsReflexive = other === other; - if (value > other || !valIsReflexive || value === undefined && othIsReflexive) { - return 1; - } - if (value < other || !othIsReflexive || other === undefined && valIsReflexive) { - return -1; - } - } - return 0; - } - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to search. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromRight) { - var length = array.length, index = fromRight ? length : -1; - while (fromRight ? index-- : ++index < length) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } - /** - * The base implementation of `_.indexOf` without support for binary searches. - * - * @private - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - if (value !== value) { - return indexOfNaN(array, fromIndex); - } - var index = fromIndex - 1, length = array.length; - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - /** - * The base implementation of `_.isFunction` without support for environments - * with incorrect `typeof` results. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - */ - function baseIsFunction(value) { - // Avoid a Chakra JIT bug in compatibility modes of IE 11. - // See https://github.com/jashkenas/underscore/issues/1621 for more details. - return typeof value == 'function' || false; - } - /** - * Converts `value` to a string if it is not one. An empty string is returned - * for `null` or `undefined` values. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - if (typeof value == 'string') { - return value; - } - return value == null ? '' : value + ''; - } - /** - * Used by `_.max` and `_.min` as the default callback for string values. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the code unit of the first character of the string. - */ - function charAtCallback(string) { - return string.charCodeAt(0); - } - /** - * Used by `_.trim` and `_.trimLeft` to get the index of the first character - * of `string` that is not found in `chars`. - * - * @private - * @param {string} string The string to inspect. - * @param {string} chars The characters to find. - * @returns {number} Returns the index of the first character not found in `chars`. - */ - function charsLeftIndex(string, chars) { - var index = -1, length = string.length; - while (++index < length && chars.indexOf(string.charAt(index)) > -1) { - } - return index; - } - /** - * Used by `_.trim` and `_.trimRight` to get the index of the last character - * of `string` that is not found in `chars`. - * - * @private - * @param {string} string The string to inspect. - * @param {string} chars The characters to find. - * @returns {number} Returns the index of the last character not found in `chars`. - */ - function charsRightIndex(string, chars) { - var index = string.length; - while (index-- && chars.indexOf(string.charAt(index)) > -1) { - } - return index; - } - /** - * Used by `_.sortBy` to compare transformed elements of a collection and stable - * sort them in ascending order. - * - * @private - * @param {Object} object The object to compare to `other`. - * @param {Object} other The object to compare to `object`. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareAscending(object, other) { - return baseCompareAscending(object.criteria, other.criteria) || object.index - other.index; - } - /** - * Used by `_.sortByOrder` to compare multiple properties of each element - * in a collection and stable sort them in the following order: - * - * If `orders` is unspecified, sort in ascending order for all properties. - * Otherwise, for each property, sort in ascending order if its corresponding value in - * orders is true, and descending order if false. - * - * @private - * @param {Object} object The object to compare to `other`. - * @param {Object} other The object to compare to `object`. - * @param {boolean[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, objCriteria = object.criteria, othCriteria = other.criteria, length = objCriteria.length, ordersLength = orders.length; - while (++index < length) { - var result = baseCompareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - return result * (orders[index] ? 1 : -1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://code.google.com/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - /** - * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - function deburrLetter(letter) { - return deburredLetters[letter]; - } - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeHtmlChar(chr) { - return htmlEscapes[chr]; - } - /** - * Used by `_.template` to escape characters for inclusion in compiled - * string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - return '\\' + stringEscapes[chr]; - } - /** - * Gets the index at which the first occurrence of `NaN` is found in `array`. - * - * @private - * @param {Array} array The array to search. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched `NaN`, else `-1`. - */ - function indexOfNaN(array, fromIndex, fromRight) { - var length = array.length, index = fromIndex + (fromRight ? 0 : -1); - while (fromRight ? index-- : ++index < length) { - var other = array[index]; - if (other !== other) { - return index; - } - } - return -1; - } - /** - * Checks if `value` is object-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } - /** - * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a - * character code is whitespace. - * - * @private - * @param {number} charCode The character code to inspect. - * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. - */ - function isSpace(charCode) { - return charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160 || charCode == 5760 || charCode == 6158 || charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279); - } - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, length = array.length, resIndex = -1, result = []; - while (++index < length) { - if (array[index] === placeholder) { - array[index] = PLACEHOLDER; - result[++resIndex] = index; - } - } - return result; - } - /** - * An implementation of `_.uniq` optimized for sorted arrays without support - * for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The function invoked per iteration. - * @returns {Array} Returns the new duplicate-value-free array. - */ - function sortedUniq(array, iteratee) { - var seen, index = -1, length = array.length, resIndex = -1, result = []; - while (++index < length) { - var value = array[index], computed = iteratee ? iteratee(value, index, array) : value; - if (!index || seen !== computed) { - seen = computed; - result[++resIndex] = value; - } - } - return result; - } - /** - * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace - * character of `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the index of the first non-whitespace character. - */ - function trimmedLeftIndex(string) { - var index = -1, length = string.length; - while (++index < length && isSpace(string.charCodeAt(index))) { - } - return index; - } - /** - * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace - * character of `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the index of the last non-whitespace character. - */ - function trimmedRightIndex(string) { - var index = string.length; - while (index-- && isSpace(string.charCodeAt(index))) { - } - return index; - } - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - function unescapeHtmlChar(chr) { - return htmlUnescapes[chr]; - } - /** - * Create a new pristine `lodash` function using the given `context` object. - * - * @static - * @memberOf _ - * @category Utility - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // using `context` to mock `Date#getTime` use in `_.now` - * var mock = _.runInContext({ - * 'Date': function() { - * return { 'getTime': getTimeMock }; - * } - * }); - * - * // or creating a suped-up `defer` in Node.js - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - function runInContext(context) { - // Avoid issues with some ES3 environments that attempt to use values, named - // after built-in constructors like `Object`, for the creation of literals. - // ES5 clears this up by stating that literals must use built-in constructors. - // See https://es5.github.io/#x11.1.5 for more details. - context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; - /** Native constructor references. */ - var Array = context.Array, Date = context.Date, Error = context.Error, Function = context.Function, Math = context.Math, Number = context.Number, Object = context.Object, RegExp = context.RegExp, String = context.String, TypeError = context.TypeError; - /** Used for native method references. */ - var arrayProto = Array.prototype, objectProto = Object.prototype, stringProto = String.prototype; - /** Used to detect DOM support. */ - var document = (document = context.window) && document.document; - /** Used to resolve the decompiled source of functions. */ - var fnToString = Function.prototype.toString; - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - /** Used to generate unique IDs. */ - var idCounter = 0; - /** - * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) - * of values. - */ - var objToString = objectProto.toString; - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = context._; - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + escapeRegExp(objToString).replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'); - /** Native method references. */ - var ArrayBuffer = isNative(ArrayBuffer = context.ArrayBuffer) && ArrayBuffer, bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice, ceil = Math.ceil, clearTimeout = context.clearTimeout, floor = Math.floor, getOwnPropertySymbols = isNative(getOwnPropertySymbols = Object.getOwnPropertySymbols) && getOwnPropertySymbols, getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, push = arrayProto.push, preventExtensions = isNative(preventExtensions = Object.preventExtensions) && preventExtensions, propertyIsEnumerable = objectProto.propertyIsEnumerable, Set = isNative(Set = context.Set) && Set, setTimeout = context.setTimeout, splice = arrayProto.splice, Uint8Array = isNative(Uint8Array = context.Uint8Array) && Uint8Array, WeakMap = isNative(WeakMap = context.WeakMap) && WeakMap; - /** Used to clone array buffers. */ - var Float64Array = function () { - // Safari 5 errors when using an array buffer to initialize a typed array - // where the array buffer's `byteLength` is not a multiple of the typed - // array's `BYTES_PER_ELEMENT`. - try { - var func = isNative(func = context.Float64Array) && func, result = new func(new ArrayBuffer(10), 0, 1) && func; - } catch (e) { - } - return result; - }(); - /** Used as `baseAssign`. */ - var nativeAssign = function () { - // Avoid `Object.assign` in Firefox 34-37 which have an early implementation - // with a now defunct try/catch behavior. See https://bugzilla.mozilla.org/show_bug.cgi?id=1103344 - // for more details. - // - // Use `Object.preventExtensions` on a plain object instead of simply using - // `Object('x')` because Chrome and IE fail to throw an error when attempting - // to assign values to readonly indexes of strings. - var func = preventExtensions && isNative(func = Object.assign) && func; - try { - if (func) { - var object = preventExtensions({ '1': 0 }); - object[0] = 1; - } - } catch (e) { - // Only attempt in strict mode. - try { - func(object, 'xo'); - } catch (e) { - } - return !object[1] && func; - } - return false; - }(); - /* Native method references for those with the same name as other `lodash` methods. */ - var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray, nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate, nativeIsFinite = context.isFinite, nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, nativeMax = Math.max, nativeMin = Math.min, nativeNow = isNative(nativeNow = Date.now) && nativeNow, nativeNumIsFinite = isNative(nativeNumIsFinite = Number.isFinite) && nativeNumIsFinite, nativeParseInt = context.parseInt, nativeRandom = Math.random; - /** Used as references for `-Infinity` and `Infinity`. */ - var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, POSITIVE_INFINITY = Number.POSITIVE_INFINITY; - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1, MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - /** Used as the size, in bytes, of each `Float64Array` element. */ - var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; - /** - * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) - * of an array-like value. - */ - var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap(); - /** Used to lookup unminified function names. */ - var realNames = {}; - /** - * Creates a `lodash` object which wraps `value` to enable implicit chaining. - * Methods that operate on and return arrays, collections, and functions can - * be chained together. Methods that return a boolean or single value will - * automatically end the chain returning the unwrapped value. Explicit chaining - * may be enabled using `_.chain`. The execution of chained methods is lazy, - * that is, execution is deferred until `_#value` is implicitly or explicitly - * called. - * - * Lazy evaluation allows several methods to support shortcut fusion. Shortcut - * fusion is an optimization that merges iteratees to avoid creating intermediate - * arrays and reduce the number of iteratee executions. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, - * `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, - * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, - * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, - * and `where` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, - * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, - * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`, - * `difference`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `fill`, - * `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, `forEach`, - * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`, - * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, - * `keysIn`, `map`, `mapValues`, `matches`, `matchesProperty`, `memoize`, - * `merge`, `mixin`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, - * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, - * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `reverse`, - * `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, `sortByOrder`, `splice`, - * `spread`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, - * `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, `transform`, - * `union`, `uniq`, `unshift`, `unzip`, `values`, `valuesIn`, `where`, - * `without`, `wrap`, `xor`, `zip`, and `zipObject` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`, - * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, - * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `has`, - * `identity`, `includes`, `indexOf`, `inRange`, `isArguments`, `isArray`, - * `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`, `isFinite` - * `isFunction`, `isMatch`, `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, - * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, - * `join`, `kebabCase`, `last`, `lastIndexOf`, `max`, `min`, `noConflict`, - * `noop`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, - * `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, `startsWith`, - * `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, `unescape`, - * `uniqueId`, `value`, and `words` - * - * The wrapper method `sample` will return a wrapped value when `n` is provided, - * otherwise an unwrapped value is returned. - * - * @name _ - * @constructor - * @category Chain - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var wrapped = _([1, 2, 3]); - * - * // returns an unwrapped value - * wrapped.reduce(function(total, n) { - * return total + n; - * }); - * // => 6 - * - * // returns a wrapped value - * var squares = wrapped.map(function(n) { - * return n * n; - * }); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } - /** - * The function whose prototype all chaining wrappers inherit from. - * - * @private - */ - function baseLodash() { - } - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable chaining for all wrapper methods. - * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. - */ - function LodashWrapper(value, chainAll, actions) { - this.__wrapped__ = value; - this.__actions__ = actions || []; - this.__chain__ = !!chainAll; - } - /** - * An object environment feature flags. - * - * @static - * @memberOf _ - * @type Object - */ - var support = lodash.support = {}; - (function (x) { - var Ctor = function () { - this.x = x; - }, args = arguments, object = { - '0': x, - 'length': x - }, props = []; - Ctor.prototype = { - 'valueOf': x, - 'y': x - }; - for (var key in new Ctor()) { - props.push(key); - } - /** - * Detect if functions can be decompiled by `Function#toString` - * (all but Firefox OS certified apps, older Opera mobile browsers, and - * the PlayStation 3; forced `false` for Windows 8 apps). - * - * @memberOf _.support - * @type boolean - */ - support.funcDecomp = /\bthis\b/.test(function () { - return this; - }); - /** - * Detect if `Function#name` is supported (all but IE). - * - * @memberOf _.support - * @type boolean - */ - support.funcNames = typeof Function.name == 'string'; - /** - * Detect if the DOM is supported. - * - * @memberOf _.support - * @type boolean - */ - try { - support.dom = document.createDocumentFragment().nodeType === 11; - } catch (e) { - support.dom = false; - } - /** - * Detect if `arguments` object indexes are non-enumerable. - * - * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object - * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat - * `arguments` object indexes as non-enumerable and fail `hasOwnProperty` - * checks for indexes that exceed the number of function parameters and - * whose associated argument values are `0`. - * - * @memberOf _.support - * @type boolean - */ - try { - support.nonEnumArgs = !propertyIsEnumerable.call(args, 1); - } catch (e) { - support.nonEnumArgs = true; - } - }(1, 0)); - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB). Change the following template settings to use - * alternative delimiters. - * - * @static - * @memberOf _ - * @type Object - */ - lodash.templateSettings = { - 'escape': reEscape, - 'evaluate': reEvaluate, - 'interpolate': reInterpolate, - 'variable': '', - 'imports': { '_': lodash } - }; - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = null; - this.__dir__ = 1; - this.__dropCount__ = 0; - this.__filtered__ = false; - this.__iteratees__ = null; - this.__takeCount__ = POSITIVE_INFINITY; - this.__views__ = null; - } - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var actions = this.__actions__, iteratees = this.__iteratees__, views = this.__views__, result = new LazyWrapper(this.__wrapped__); - result.__actions__ = actions ? arrayCopy(actions) : null; - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = iteratees ? arrayCopy(iteratees) : null; - result.__takeCount__ = this.__takeCount__; - result.__views__ = views ? arrayCopy(views) : null; - return result; - } - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(); - if (!isArray(array)) { - return baseWrapperValue(array, this.__actions__); - } - var dir = this.__dir__, isRight = dir < 0, view = getView(0, array.length, this.__views__), start = view.start, end = view.end, length = end - start, index = isRight ? end : start - 1, takeCount = nativeMin(length, this.__takeCount__), iteratees = this.__iteratees__, iterLength = iteratees ? iteratees.length : 0, resIndex = 0, result = []; - outer: - while (length-- && resIndex < takeCount) { - index += dir; - var iterIndex = -1, value = array[index]; - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], iteratee = data.iteratee, type = data.type; - if (type == LAZY_DROP_WHILE_FLAG) { - if (data.done && (isRight ? index > data.index : index < data.index)) { - data.count = 0; - data.done = false; - } - data.index = index; - if (!data.done) { - var limit = data.limit; - if (!(data.done = limit > -1 ? data.count++ >= limit : !iteratee(value))) { - continue outer; - } - } - } else { - var computed = iteratee(value); - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - } - result[resIndex++] = value; - } - return result; - } - /** - * Creates a cache object to store key/value pairs. - * - * @private - * @static - * @name Cache - * @memberOf _.memoize - */ - function MapCache() { - this.__data__ = {}; - } - /** - * Removes `key` and its value from the cache. - * - * @private - * @name delete - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. - */ - function mapDelete(key) { - return this.has(key) && delete this.__data__[key]; - } - /** - * Gets the cached value for `key`. - * - * @private - * @name get - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to get. - * @returns {*} Returns the cached value. - */ - function mapGet(key) { - return key == '__proto__' ? undefined : this.__data__[key]; - } - /** - * Checks if a cached value for `key` exists. - * - * @private - * @name has - * @memberOf _.memoize.Cache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapHas(key) { - return key != '__proto__' && hasOwnProperty.call(this.__data__, key); - } - /** - * Sets `value` to `key` of the cache. - * - * @private - * @name set - * @memberOf _.memoize.Cache - * @param {string} key The key of the value to cache. - * @param {*} value The value to cache. - * @returns {Object} Returns the cache object. - */ - function mapSet(key, value) { - if (key != '__proto__') { - this.__data__[key] = value; - } - return this; - } - /** - * - * Creates a cache object to store unique values. - * - * @private - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var length = values ? values.length : 0; - this.data = { - 'hash': nativeCreate(null), - 'set': new Set() - }; - while (length--) { - this.push(values[length]); - } - } - /** - * Checks if `value` is in `cache` mimicking the return signature of - * `_.indexOf` by returning `0` if the value is found, else `-1`. - * - * @private - * @param {Object} cache The cache to search. - * @param {*} value The value to search for. - * @returns {number} Returns `0` if `value` is found, else `-1`. - */ - function cacheIndexOf(cache, value) { - var data = cache.data, result = typeof value == 'string' || isObject(value) ? data.set.has(value) : data.hash[value]; - return result ? 0 : -1; - } - /** - * Adds `value` to the cache. - * - * @private - * @name push - * @memberOf SetCache - * @param {*} value The value to cache. - */ - function cachePush(value) { - var data = this.data; - if (typeof value == 'string' || isObject(value)) { - data.set.add(value); - } else { - data.hash[value] = true; - } - } - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function arrayCopy(source, array) { - var index = -1, length = source.length; - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - /** - * A specialized version of `_.forEach` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, length = array.length; - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } - /** - * A specialized version of `_.forEachRight` for arrays without support for - * callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEachRight(array, iteratee) { - var length = array.length; - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } - } - return array; - } - /** - * A specialized version of `_.every` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, length = array.length; - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - /** - * A specialized version of `_.filter` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, length = array.length, resIndex = -1, result = []; - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[++resIndex] = value; - } - } - return result; - } - /** - * A specialized version of `_.map` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, length = array.length, result = Array(length); - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - /** - * A specialized version of `_.max` for arrays without support for iteratees. - * - * @private - * @param {Array} array The array to iterate over. - * @returns {*} Returns the maximum value. - */ - function arrayMax(array) { - var index = -1, length = array.length, result = NEGATIVE_INFINITY; - while (++index < length) { - var value = array[index]; - if (value > result) { - result = value; - } - } - return result; - } - /** - * A specialized version of `_.min` for arrays without support for iteratees. - * - * @private - * @param {Array} array The array to iterate over. - * @returns {*} Returns the minimum value. - */ - function arrayMin(array) { - var index = -1, length = array.length, result = POSITIVE_INFINITY; - while (++index < length) { - var value = array[index]; - if (value < result) { - result = value; - } - } - return result; - } - /** - * A specialized version of `_.reduce` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the first element of `array` - * as the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initFromArray) { - var index = -1, length = array.length; - if (initFromArray && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - /** - * A specialized version of `_.reduceRight` for arrays without support for - * callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initFromArray] Specify using the last element of `array` - * as the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initFromArray) { - var length = array.length; - if (initFromArray && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } - /** - * A specialized version of `_.some` for arrays without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, length = array.length; - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } - /** - * A specialized version of `_.sum` for arrays without support for iteratees. - * - * @private - * @param {Array} array The array to iterate over. - * @returns {number} Returns the sum. - */ - function arraySum(array) { - var length = array.length, result = 0; - while (length--) { - result += +array[length] || 0; - } - return result; - } - /** - * Used by `_.defaults` to customize its `_.assign` use. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignDefaults(objectValue, sourceValue) { - return objectValue === undefined ? sourceValue : objectValue; - } - /** - * Used by `_.template` to customize its `_.assign` use. - * - * **Note:** This function is like `assignDefaults` except that it ignores - * inherited property values when checking if a property is `undefined`. - * - * @private - * @param {*} objectValue The destination object property value. - * @param {*} sourceValue The source object property value. - * @param {string} key The key associated with the object and source values. - * @param {Object} object The destination object. - * @returns {*} Returns the value to assign to the destination object. - */ - function assignOwnDefaults(objectValue, sourceValue, key, object) { - return objectValue === undefined || !hasOwnProperty.call(object, key) ? sourceValue : objectValue; - } - /** - * A specialized version of `_.assign` for customizing assigned values without - * support for argument juggling, multiple sources, and `this` binding `customizer` - * functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - */ - function assignWith(object, source, customizer) { - var props = keys(source); - push.apply(props, getSymbols(source)); - var index = -1, length = props.length; - while (++index < length) { - var key = props[index], value = object[key], result = customizer(value, source[key], key, object, source); - if ((result === result ? result !== value : value === value) || value === undefined && !(key in object)) { - object[key] = result; - } - } - return object; - } - /** - * The base implementation of `_.assign` without support for argument juggling, - * multiple sources, and `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - var baseAssign = nativeAssign || function (object, source) { - return source == null ? object : baseCopy(source, getSymbols(source), baseCopy(source, keys(source), object)); - }; - /** - * The base implementation of `_.at` without support for string collections - * and individual key arguments. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {number[]|string[]} props The property names or indexes of elements to pick. - * @returns {Array} Returns the new array of picked elements. - */ - function baseAt(collection, props) { - var index = -1, isNil = collection == null, isArr = !isNil && isArrayLike(collection), length = isArr && collection.length, propsLength = props.length, result = Array(propsLength); - while (++index < propsLength) { - var key = props[index]; - if (isArr) { - result[index] = isIndex(key, length) ? collection[key] : undefined; - } else { - result[index] = isNil ? undefined : collection[key]; - } - } - return result; - } - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property names to copy. - * @param {Object} [object={}] The object to copy properties to. - * @returns {Object} Returns `object`. - */ - function baseCopy(source, props, object) { - object || (object = {}); - var index = -1, length = props.length; - while (++index < length) { - var key = props[index]; - object[key] = source[key]; - } - return object; - } - /** - * The base implementation of `_.callback` which supports specifying the - * number of arguments to provide to `func`. - * - * @private - * @param {*} [func=_.identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function baseCallback(func, thisArg, argCount) { - var type = typeof func; - if (type == 'function') { - return thisArg === undefined ? func : bindCallback(func, thisArg, argCount); - } - if (func == null) { - return identity; - } - if (type == 'object') { - return baseMatches(func); - } - return thisArg === undefined ? property(func) : baseMatchesProperty(func, thisArg); - } - /** - * The base implementation of `_.clone` without support for argument juggling - * and `this` binding `customizer` functions. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The object `value` belongs to. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates clones with source counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { - var result; - if (customizer) { - result = object ? customizer(value, key, object) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return arrayCopy(value, result); - } - } else { - var tag = objToString.call(value), isFunc = tag == funcTag; - if (tag == objectTag || tag == argsTag || isFunc && !object) { - result = initCloneObject(isFunc ? {} : value); - if (!isDeep) { - return baseAssign(result, value); - } - } else { - return cloneableTags[tag] ? initCloneByTag(value, tag, isDeep) : object ? value : {}; - } - } - // Check for circular references and return corresponding clone. - stackA || (stackA = []); - stackB || (stackB = []); - var length = stackA.length; - while (length--) { - if (stackA[length] == value) { - return stackB[length]; - } - } - // Add the source value to the stack of traversed objects and associate it with its clone. - stackA.push(value); - stackB.push(result); - // Recursively populate clone (susceptible to call stack limits). - (isArr ? arrayEach : baseForOwn)(value, function (subValue, key) { - result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); - }); - return result; - } - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = function () { - function Object() { - } - return function (prototype) { - if (isObject(prototype)) { - Object.prototype = prototype; - var result = new Object(); - Object.prototype = null; - } - return result || context.Object(); - }; - }(); - /** - * The base implementation of `_.delay` and `_.defer` which accepts an index - * of where to slice the arguments to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Object} args The arguments provide to `func`. - * @returns {number} Returns the timer id. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function () { - func.apply(undefined, args); - }, wait); - } - /** - * The base implementation of `_.difference` which accepts a single array - * of values to exclude. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values) { - var length = array ? array.length : 0, result = []; - if (!length) { - return result; - } - var index = -1, indexOf = getIndexOf(), isCommon = indexOf == baseIndexOf, cache = isCommon && values.length >= 200 ? createCache(values) : null, valuesLength = values.length; - if (cache) { - indexOf = cacheIndexOf; - isCommon = false; - values = cache; - } - outer: - while (++index < length) { - var value = array[index]; - if (isCommon && value === value) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === value) { - continue outer; - } - } - result.push(value); - } else if (indexOf(values, value, 0) < 0) { - result.push(value); - } - } - return result; - } - /** - * The base implementation of `_.forEach` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object|string} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - /** - * The base implementation of `_.forEachRight` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object|string} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); - /** - * The base implementation of `_.every` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function (value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; - start = start == null ? 0 : +start || 0; - if (start < 0) { - start = -start > length ? 0 : length + start; - } - end = end === undefined || end > length ? length : +end || 0; - if (end < 0) { - end += length; - } - length = start > end ? 0 : end >>> 0; - start >>>= 0; - while (start < length) { - array[start++] = value; - } - return array; - } - /** - * The base implementation of `_.filter` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function (value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } - /** - * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, - * without support for callback shorthands and `this` binding, which iterates - * over `collection` using the provided `eachFunc`. - * - * @private - * @param {Array|Object|string} collection The collection to search. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @param {boolean} [retKey] Specify returning the key of the found element - * instead of the element itself. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFind(collection, predicate, eachFunc, retKey) { - var result; - eachFunc(collection, function (value, key, collection) { - if (predicate(value, key, collection)) { - result = retKey ? key : value; - return false; - } - }); - return result; - } - /** - * The base implementation of `_.flatten` with added support for restricting - * flattening and specifying the start index. - * - * @private - * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, isDeep, isStrict) { - var index = -1, length = array.length, resIndex = -1, result = []; - while (++index < length) { - var value = array[index]; - if (isObjectLike(value) && isArrayLike(value) && (isStrict || isArray(value) || isArguments(value))) { - if (isDeep) { - // Recursively flatten arrays (susceptible to call stack limits). - value = baseFlatten(value, isDeep, isStrict); - } - var valIndex = -1, valLength = value.length; - while (++valIndex < valLength) { - result[++resIndex] = value[valIndex]; - } - } else if (!isStrict) { - result[++resIndex] = value; - } - } - return result; - } - /** - * The base implementation of `baseForIn` and `baseForOwn` which iterates - * over `object` properties returned by `keysFunc` invoking `iteratee` for - * each property. Iteratee functions may exit iteration early by explicitly - * returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - /** - * The base implementation of `_.forIn` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForIn(object, iteratee) { - return baseFor(object, iteratee, keysIn); - } - /** - * The base implementation of `_.forOwn` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return baseFor(object, iteratee, keys); - } - /** - * The base implementation of `_.forOwnRight` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return baseForRight(object, iteratee, keys); - } - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from those provided. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the new array of filtered property names. - */ - function baseFunctions(object, props) { - var index = -1, length = props.length, resIndex = -1, result = []; - while (++index < length) { - var key = props[index]; - if (isFunction(object[key])) { - result[++resIndex] = key; - } - } - return result; - } - /** - * The base implementation of `get` without support for string paths - * and default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path of the property to get. - * @param {string} [pathKey] The key representation of path. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path, pathKey) { - if (object == null) { - return; - } - if (pathKey !== undefined && pathKey in toObject(object)) { - path = [pathKey]; - } - var index = -1, length = path.length; - while (object != null && ++index < length) { - object = object[path[index]]; - } - return index && index == length ? object : undefined; - } - /** - * The base implementation of `_.isEqual` without support for `this` binding - * `customizer` functions. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparing values. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { - // Exit early for identical values. - if (value === other) { - return true; - } - var valType = typeof value, othType = typeof other; - // Exit early for unlike primitive values. - if (valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object' || value == null || other == null) { - // Return `false` unless both values are `NaN`. - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); - } - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing objects. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA=[]] Tracks traversed `value` objects. - * @param {Array} [stackB=[]] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objIsArr = isArray(object), othIsArr = isArray(other), objTag = arrayTag, othTag = arrayTag; - if (!objIsArr) { - objTag = objToString.call(object); - if (objTag == argsTag) { - objTag = objectTag; - } else if (objTag != objectTag) { - objIsArr = isTypedArray(object); - } - } - if (!othIsArr) { - othTag = objToString.call(other); - if (othTag == argsTag) { - othTag = objectTag; - } else if (othTag != objectTag) { - othIsArr = isTypedArray(other); - } - } - var objIsObj = objTag == objectTag, othIsObj = othTag == objectTag, isSameTag = objTag == othTag; - if (isSameTag && !(objIsArr || objIsObj)) { - return equalByTag(object, other, objTag); - } - if (!isLoose) { - var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - if (valWrapped || othWrapped) { - return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); - } - } - if (!isSameTag) { - return false; - } - // Assume cyclic values are equal. - // For more information on detecting circular references see https://es5.github.io/#JO. - stackA || (stackA = []); - stackB || (stackB = []); - var length = stackA.length; - while (length--) { - if (stackA[length] == object) { - return stackB[length] == other; - } - } - // Add `object` and `other` to the stack of traversed objects. - stackA.push(object); - stackB.push(other); - var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); - stackA.pop(); - stackB.pop(); - return result; - } - /** - * The base implementation of `_.isMatch` without support for callback - * shorthands and `this` binding. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The source property names to match. - * @param {Array} values The source values to match. - * @param {Array} strictCompareFlags Strict comparison flags for source values. - * @param {Function} [customizer] The function to customize comparing objects. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, props, values, strictCompareFlags, customizer) { - var index = -1, length = props.length, noCustomizer = !customizer; - while (++index < length) { - if (noCustomizer && strictCompareFlags[index] ? values[index] !== object[props[index]] : !(props[index] in object)) { - return false; - } - } - index = -1; - while (++index < length) { - var key = props[index], objValue = object[key], srcValue = values[index]; - if (noCustomizer && strictCompareFlags[index]) { - var result = objValue !== undefined || key in object; - } else { - result = customizer ? customizer(objValue, srcValue, key) : undefined; - if (result === undefined) { - result = baseIsEqual(srcValue, objValue, customizer, true); - } - } - if (!result) { - return false; - } - } - return true; - } - /** - * The base implementation of `_.map` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, result = isArrayLike(collection) ? Array(collection.length) : []; - baseEach(collection, function (value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } - /** - * The base implementation of `_.matches` which does not clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new function. - */ - function baseMatches(source) { - var props = keys(source), length = props.length; - if (!length) { - return constant(true); - } - if (length == 1) { - var key = props[0], value = source[key]; - if (isStrictComparable(value)) { - return function (object) { - if (object == null) { - return false; - } - return object[key] === value && (value !== undefined || key in toObject(object)); - }; - } - } - var values = Array(length), strictCompareFlags = Array(length); - while (length--) { - value = source[props[length]]; - values[length] = value; - strictCompareFlags[length] = isStrictComparable(value); - } - return function (object) { - return object != null && baseIsMatch(toObject(object), props, values, strictCompareFlags); - }; - } - /** - * The base implementation of `_.matchesProperty` which does not which does - * not clone `value`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} value The value to compare. - * @returns {Function} Returns the new function. - */ - function baseMatchesProperty(path, value) { - var isArr = isArray(path), isCommon = isKey(path) && isStrictComparable(value), pathKey = path + ''; - path = toPath(path); - return function (object) { - if (object == null) { - return false; - } - var key = pathKey; - object = toObject(object); - if ((isArr || !isCommon) && !(key in object)) { - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - if (object == null) { - return false; - } - key = last(path); - object = toObject(object); - } - return object[key] === value ? value !== undefined || key in object : baseIsEqual(value, object[key], null, true); - }; - } - /** - * The base implementation of `_.merge` without support for argument juggling, - * multiple sources, and `this` binding `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {Function} [customizer] The function to customize merging properties. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {Object} Returns `object`. - */ - function baseMerge(object, source, customizer, stackA, stackB) { - if (!isObject(object)) { - return object; - } - var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)); - if (!isSrcArr) { - var props = keys(source); - push.apply(props, getSymbols(source)); - } - arrayEach(props || source, function (srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObjectLike(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); - } else { - var value = object[key], result = customizer ? customizer(value, srcValue, key, object, source) : undefined, isCommon = result === undefined; - if (isCommon) { - result = srcValue; - } - if ((isSrcArr || result !== undefined) && (isCommon || (result === result ? result !== value : value === value))) { - object[key] = result; - } - } - }); - return object; - } - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize merging properties. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { - var length = stackA.length, srcValue = source[key]; - while (length--) { - if (stackA[length] == srcValue) { - object[key] = stackB[length]; - return; - } - } - var value = object[key], result = customizer ? customizer(value, srcValue, key, object, source) : undefined, isCommon = result === undefined; - if (isCommon) { - result = srcValue; - if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { - result = isArray(value) ? value : isArrayLike(value) ? arrayCopy(value) : []; - } else if (isPlainObject(srcValue) || isArguments(srcValue)) { - result = isArguments(value) ? toPlainObject(value) : isPlainObject(value) ? value : {}; - } else { - isCommon = false; - } - } - // Add the source value to the stack of traversed objects and associate - // it with its merged value. - stackA.push(srcValue); - stackB.push(result); - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); - } else if (result === result ? result !== value : value === value) { - object[key] = result; - } - } - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. - */ - function baseProperty(key) { - return function (object) { - return object == null ? undefined : object[key]; - }; - } - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new function. - */ - function basePropertyDeep(path) { - var pathKey = path + ''; - path = toPath(path); - return function (object) { - return baseGet(object, path, pathKey); - }; - } - /** - * The base implementation of `_.pullAt` without support for individual - * index arguments and capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0; - while (length--) { - var index = parseFloat(indexes[length]); - if (index != previous && isIndex(index)) { - var previous = index; - splice.call(array, index, 1); - } - } - return array; - } - /** - * The base implementation of `_.random` without support for argument juggling - * and returning floating-point numbers. - * - * @private - * @param {number} min The minimum possible value. - * @param {number} max The maximum possible value. - * @returns {number} Returns the random number. - */ - function baseRandom(min, max) { - return min + floor(nativeRandom() * (max - min + 1)); - } - /** - * The base implementation of `_.reduce` and `_.reduceRight` without support - * for callback shorthands and `this` binding, which iterates over `collection` - * using the provided `eachFunc`. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initFromCollection Specify using the first or last element - * of `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { - eachFunc(collection, function (value, index, collection) { - accumulator = initFromCollection ? (initFromCollection = false, value) : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - /** - * The base implementation of `setData` without support for hot loop detection. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function (func, data) { - metaMap.set(func, data); - return func; - }; - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, length = array.length; - start = start == null ? 0 : +start || 0; - if (start < 0) { - start = -start > length ? 0 : length + start; - } - end = end === undefined || end > length ? length : +end || 0; - if (end < 0) { - end += length; - } - length = start > end ? 0 : end - start >>> 0; - start >>>= 0; - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - /** - * The base implementation of `_.some` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; - baseEach(collection, function (value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - /** - * The base implementation of `_.sortBy` which uses `comparer` to define - * the sort order of `array` and replaces criteria objects with their - * corresponding values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - /** - * The base implementation of `_.sortByOrder` without param guards. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseSortByOrder(collection, iteratees, orders) { - var callback = getCallback(), index = -1; - iteratees = arrayMap(iteratees, function (iteratee) { - return callback(iteratee); - }); - var result = baseMap(collection, function (value) { - var criteria = arrayMap(iteratees, function (iteratee) { - return iteratee(value); - }); - return { - 'criteria': criteria, - 'index': ++index, - 'value': value - }; - }); - return baseSortBy(result, function (object, other) { - return compareMultiple(object, other, orders); - }); - } - /** - * The base implementation of `_.sum` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(collection, iteratee) { - var result = 0; - baseEach(collection, function (value, index, collection) { - result += +iteratee(value, index, collection) || 0; - }); - return result; - } - /** - * The base implementation of `_.uniq` without support for callback shorthands - * and `this` binding. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The function invoked per iteration. - * @returns {Array} Returns the new duplicate-value-free array. - */ - function baseUniq(array, iteratee) { - var index = -1, indexOf = getIndexOf(), length = array.length, isCommon = indexOf == baseIndexOf, isLarge = isCommon && length >= 200, seen = isLarge ? createCache() : null, result = []; - if (seen) { - indexOf = cacheIndexOf; - isCommon = false; - } else { - isLarge = false; - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], computed = iteratee ? iteratee(value, index, array) : value; - if (isCommon && value === value) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } else if (indexOf(seen, computed, 0) < 0) { - if (iteratee || isLarge) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - var index = -1, length = props.length, result = Array(length); - while (++index < length) { - result[index] = object[props[index]]; - } - return result; - } - /** - * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, - * and `_.takeWhile` without support for callback shorthands and `this` binding. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, index = fromRight ? length : -1; - while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) { - } - return isDrop ? baseSlice(array, fromRight ? 0 : index, fromRight ? index + 1 : length) : baseSlice(array, fromRight ? index + 1 : 0, fromRight ? length : index); - } - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to peform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - var index = -1, length = actions.length; - while (++index < length) { - var args = [result], action = actions[index]; - push.apply(args, action.args); - result = action.func.apply(action.thisArg, args); - } - return result; - } - /** - * Performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndex(array, value, retHighest) { - var low = 0, high = array ? array.length : low; - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = low + high >>> 1, computed = array[mid]; - if (retHighest ? computed <= value : computed < value) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return binaryIndexBy(array, value, identity, retHighest); - } - /** - * This function is like `binaryIndex` except that it invokes `iteratee` for - * `value` and each element of `array` to compute their sort ranking. The - * iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The function invoked per iteration. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function binaryIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - var low = 0, high = array ? array.length : 0, valIsNaN = value !== value, valIsUndef = value === undefined; - while (low < high) { - var mid = floor((low + high) / 2), computed = iteratee(array[mid]), isReflexive = computed === computed; - if (valIsNaN) { - var setLow = isReflexive || retHighest; - } else if (valIsUndef) { - setLow = isReflexive && (retHighest || computed !== undefined); - } else { - setLow = retHighest ? computed <= value : computed < value; - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } - /** - * A specialized version of `baseCallback` which only supports `this` binding - * and specifying the number of arguments to provide to `func`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {number} [argCount] The number of arguments to provide to `func`. - * @returns {Function} Returns the callback. - */ - function bindCallback(func, thisArg, argCount) { - if (typeof func != 'function') { - return identity; - } - if (thisArg === undefined) { - return func; - } - switch (argCount) { - case 1: - return function (value) { - return func.call(thisArg, value); - }; - case 3: - return function (value, index, collection) { - return func.call(thisArg, value, index, collection); - }; - case 4: - return function (accumulator, value, index, collection) { - return func.call(thisArg, accumulator, value, index, collection); - }; - case 5: - return function (value, other, key, object, source) { - return func.call(thisArg, value, other, key, object, source); - }; - } - return function () { - return func.apply(thisArg, arguments); - }; - } - /** - * Creates a clone of the given array buffer. - * - * @private - * @param {ArrayBuffer} buffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function bufferClone(buffer) { - return bufferSlice.call(buffer, 0); - } - if (!bufferSlice) { - // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`. - bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function (buffer) { - var byteLength = buffer.byteLength, floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0, offset = floatLength * FLOAT64_BYTES_PER_ELEMENT, result = new ArrayBuffer(byteLength); - if (floatLength) { - var view = new Float64Array(result, 0, floatLength); - view.set(new Float64Array(buffer, 0, floatLength)); - } - if (byteLength != offset) { - view = new Uint8Array(result, offset); - view.set(new Uint8Array(buffer, offset)); - } - return result; - }; - } - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array|Object} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders) { - var holdersLength = holders.length, argsIndex = -1, argsLength = nativeMax(args.length - holdersLength, 0), leftIndex = -1, leftLength = partials.length, result = Array(argsLength + leftLength); - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - while (argsLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array|Object} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders) { - var holdersIndex = -1, holdersLength = holders.length, argsIndex = -1, argsLength = nativeMax(args.length - holdersLength, 0), rightIndex = -1, rightLength = partials.length, result = Array(argsLength + rightLength); - while (++argsIndex < argsLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - return result; - } - /** - * Creates a function that aggregates a collection, creating an accumulator - * object composed from the results of running each element in the collection - * through an iteratee. - * - * **Note:** This function is used to create `_.countBy`, `_.groupBy`, `_.indexBy`, - * and `_.partition`. - * - * @private - * @param {Function} setter The function to set keys and values of the accumulator object. - * @param {Function} [initializer] The function to initialize the accumulator object. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function (collection, iteratee, thisArg) { - var result = initializer ? initializer() : {}; - iteratee = getCallback(iteratee, thisArg, 3); - if (isArray(collection)) { - var index = -1, length = collection.length; - while (++index < length) { - var value = collection[index]; - setter(result, value, iteratee(value, index, collection), collection); - } - } else { - baseEach(collection, function (value, key, collection) { - setter(result, value, iteratee(value, key, collection), collection); - }); - } - return result; - }; - } - /** - * Creates a function that assigns properties of source object(s) to a given - * destination object. - * - * **Note:** This function is used to create `_.assign`, `_.defaults`, and `_.merge`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return restParam(function (object, sources) { - var index = -1, length = object == null ? 0 : sources.length, customizer = length > 2 && sources[length - 2], guard = length > 2 && sources[2], thisArg = length > 1 && sources[length - 1]; - if (typeof customizer == 'function') { - customizer = bindCallback(customizer, thisArg, 5); - length -= 2; - } else { - customizer = typeof thisArg == 'function' ? thisArg : null; - length -= customizer ? 1 : 0; - } - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? null : customizer; - length = 1; - } - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, customizer); - } - } - return object; - }); - } - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function (collection, iteratee) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - return eachFunc(collection, iteratee); - } - var index = fromRight ? length : -1, iterable = toObject(collection); - while (fromRight ? index-- : ++index < length) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - /** - * Creates a base function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function (object, iteratee, keysFunc) { - var iterable = toObject(object), props = keysFunc(object), length = props.length, index = fromRight ? length : -1; - while (fromRight ? index-- : ++index < length) { - var key = props[index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - /** - * Creates a function that wraps `func` and invokes it with the `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to bind. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new bound function. - */ - function createBindWrapper(func, thisArg) { - var Ctor = createCtorWrapper(func); - function wrapper() { - var fn = this && this !== root && this instanceof wrapper ? Ctor : func; - return fn.apply(thisArg, arguments); - } - return wrapper; - } - /** - * Creates a `Set` cache object to optimize linear searches of large arrays. - * - * @private - * @param {Array} [values] The values to cache. - * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. - */ - var createCache = !(nativeCreate && Set) ? constant(null) : function (values) { - return new SetCache(values); - }; - /** - * Creates a function that produces compound words out of the words in a - * given string. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function (string) { - var index = -1, array = words(deburr(string)), length = array.length, result = ''; - while (++index < length) { - result = callback(result, array[index], index); - } - return result; - }; - } - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtorWrapper(Ctor) { - return function () { - var thisBinding = baseCreate(Ctor.prototype), result = Ctor.apply(thisBinding, arguments); - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - /** - * Creates a `_.curry` or `_.curryRight` function. - * - * @private - * @param {boolean} flag The curry bit flag. - * @returns {Function} Returns the new curry function. - */ - function createCurry(flag) { - function curryFunc(func, arity, guard) { - if (guard && isIterateeCall(func, arity, guard)) { - arity = null; - } - var result = createWrapper(func, flag, null, null, null, null, null, arity); - result.placeholder = curryFunc.placeholder; - return result; - } - return curryFunc; - } - /** - * Creates a `_.max` or `_.min` function. - * - * @private - * @param {Function} arrayFunc The function to get the extremum value from an array. - * @param {boolean} [isMin] Specify returning the minimum, instead of the maximum, - * extremum value. - * @returns {Function} Returns the new extremum function. - */ - function createExtremum(arrayFunc, isMin) { - return function (collection, iteratee, thisArg) { - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = null; - } - var func = getCallback(), noIteratee = iteratee == null; - if (!(func === baseCallback && noIteratee)) { - noIteratee = false; - iteratee = func(iteratee, thisArg, 3); - } - if (noIteratee) { - var isArr = isArray(collection); - if (!isArr && isString(collection)) { - iteratee = charAtCallback; - } else { - return arrayFunc(isArr ? collection : toIterable(collection)); - } - } - return extremumBy(collection, iteratee, isMin); - }; - } - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFind(eachFunc, fromRight) { - return function (collection, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); - if (isArray(collection)) { - var index = baseFindIndex(collection, predicate, fromRight); - return index > -1 ? collection[index] : undefined; - } - return baseFind(collection, predicate, eachFunc); - }; - } - /** - * Creates a `_.findIndex` or `_.findLastIndex` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new find function. - */ - function createFindIndex(fromRight) { - return function (array, predicate, thisArg) { - if (!(array && array.length)) { - return -1; - } - predicate = getCallback(predicate, thisArg, 3); - return baseFindIndex(array, predicate, fromRight); - }; - } - /** - * Creates a `_.findKey` or `_.findLastKey` function. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new find function. - */ - function createFindKey(objectFunc) { - return function (object, predicate, thisArg) { - predicate = getCallback(predicate, thisArg, 3); - return baseFind(object, predicate, objectFunc, true); - }; - } - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return function () { - var length = arguments.length; - if (!length) { - return function () { - return arguments[0]; - }; - } - var wrapper, index = fromRight ? length : -1, leftIndex = 0, funcs = Array(length); - while (fromRight ? index-- : ++index < length) { - var func = funcs[leftIndex++] = arguments[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var funcName = wrapper ? '' : getFuncName(func); - wrapper = funcName == 'wrapper' ? new LodashWrapper([]) : wrapper; - } - index = wrapper ? -1 : length; - while (++index < length) { - func = funcs[index]; - funcName = getFuncName(func); - var data = funcName == 'wrapper' ? getData(func) : null; - if (data && isLaziable(data[0]) && data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && !data[4].length && data[9] == 1) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = func.length == 1 && isLaziable(func) ? wrapper[funcName]() : wrapper.thru(func); - } - } - return function () { - var args = arguments; - if (wrapper && args.length == 1 && isArray(args[0])) { - return wrapper.plant(args[0]).value(); - } - var index = 0, result = funcs[index].apply(this, args); - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }; - } - /** - * Creates a function for `_.forEach` or `_.forEachRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createForEach(arrayFunc, eachFunc) { - return function (collection, iteratee, thisArg) { - return typeof iteratee == 'function' && thisArg === undefined && isArray(collection) ? arrayFunc(collection, iteratee) : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); - }; - } - /** - * Creates a function for `_.forIn` or `_.forInRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForIn(objectFunc) { - return function (object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); - } - return objectFunc(object, iteratee, keysIn); - }; - } - /** - * Creates a function for `_.forOwn` or `_.forOwnRight`. - * - * @private - * @param {Function} objectFunc The function to iterate over an object. - * @returns {Function} Returns the new each function. - */ - function createForOwn(objectFunc) { - return function (object, iteratee, thisArg) { - if (typeof iteratee != 'function' || thisArg !== undefined) { - iteratee = bindCallback(iteratee, thisArg, 3); - } - return objectFunc(object, iteratee); - }; - } - /** - * Creates a function for `_.mapKeys` or `_.mapValues`. - * - * @private - * @param {boolean} [isMapKeys] Specify mapping keys instead of values. - * @returns {Function} Returns the new map function. - */ - function createObjectMapper(isMapKeys) { - return function (object, iteratee, thisArg) { - var result = {}; - iteratee = getCallback(iteratee, thisArg, 3); - baseForOwn(object, function (value, key, object) { - var mapped = iteratee(value, key, object); - key = isMapKeys ? mapped : key; - value = isMapKeys ? value : mapped; - result[key] = value; - }); - return result; - }; - } - /** - * Creates a function for `_.padLeft` or `_.padRight`. - * - * @private - * @param {boolean} [fromRight] Specify padding from the right. - * @returns {Function} Returns the new pad function. - */ - function createPadDir(fromRight) { - return function (string, length, chars) { - string = baseToString(string); - return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); - }; - } - /** - * Creates a `_.partial` or `_.partialRight` function. - * - * @private - * @param {boolean} flag The partial bit flag. - * @returns {Function} Returns the new partial function. - */ - function createPartial(flag) { - var partialFunc = restParam(function (func, partials) { - var holders = replaceHolders(partials, partialFunc.placeholder); - return createWrapper(func, flag, null, partials, holders); - }); - return partialFunc; - } - /** - * Creates a function for `_.reduce` or `_.reduceRight`. - * - * @private - * @param {Function} arrayFunc The function to iterate over an array. - * @param {Function} eachFunc The function to iterate over a collection. - * @returns {Function} Returns the new each function. - */ - function createReduce(arrayFunc, eachFunc) { - return function (collection, iteratee, accumulator, thisArg) { - var initFromArray = arguments.length < 3; - return typeof iteratee == 'function' && thisArg === undefined && isArray(collection) ? arrayFunc(collection, iteratee, accumulator, initFromArray) : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); - }; - } - /** - * Creates a function that wraps `func` and invokes it with optional `this` - * binding of, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & ARY_FLAG, isBind = bitmask & BIND_FLAG, isBindKey = bitmask & BIND_KEY_FLAG, isCurry = bitmask & CURRY_FLAG, isCurryBound = bitmask & CURRY_BOUND_FLAG, isCurryRight = bitmask & CURRY_RIGHT_FLAG; - var Ctor = !isBindKey && createCtorWrapper(func), key = func; - function wrapper() { - // Avoid `arguments` object use disqualifying optimizations by - // converting it to an array before providing it to other functions. - var length = arguments.length, index = length, args = Array(length); - while (index--) { - args[index] = arguments[index]; - } - if (partials) { - args = composeArgs(args, partials, holders); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight); - } - if (isCurry || isCurryRight) { - var placeholder = wrapper.placeholder, argsHolders = replaceHolders(args, placeholder); - length -= argsHolders.length; - if (length < arity) { - var newArgPos = argPos ? arrayCopy(argPos) : null, newArity = nativeMax(arity - length, 0), newsHolders = isCurry ? argsHolders : null, newHoldersRight = isCurry ? null : argsHolders, newPartials = isCurry ? args : null, newPartialsRight = isCurry ? null : args; - bitmask |= isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG; - bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); - if (!isCurryBound) { - bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); - } - var newData = [ - func, - bitmask, - thisArg, - newPartials, - newsHolders, - newPartialsRight, - newHoldersRight, - newArgPos, - ary, - newArity - ], result = createHybridWrapper.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return result; - } - } - var thisBinding = isBind ? thisArg : this; - if (isBindKey) { - func = thisBinding[key]; - } - if (argPos) { - args = reorder(args, argPos); - } - if (isAry && ary < args.length) { - args.length = ary; - } - var fn = this && this !== root && this instanceof wrapper ? Ctor || createCtorWrapper(func) : func; - return fn.apply(thisBinding, args); - } - return wrapper; - } - /** - * Creates the padding required for `string` based on the given `length`. - * The `chars` string is truncated if the number of characters exceeds `length`. - * - * @private - * @param {string} string The string to create padding for. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the pad for `string`. - */ - function createPadding(string, length, chars) { - var strLength = string.length; - length = +length; - if (strLength >= length || !nativeIsFinite(length)) { - return ''; - } - var padLength = length - strLength; - chars = chars == null ? ' ' : chars + ''; - return repeat(chars, ceil(padLength / chars.length)).slice(0, padLength); - } - /** - * Creates a function that wraps `func` and invokes it with the optional `this` - * binding of `thisArg` and the `partials` prepended to those provided to - * the wrapper. - * - * @private - * @param {Function} func The function to partially apply arguments to. - * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to the new function. - * @returns {Function} Returns the new bound function. - */ - function createPartialWrapper(func, bitmask, thisArg, partials) { - var isBind = bitmask & BIND_FLAG, Ctor = createCtorWrapper(func); - function wrapper() { - // Avoid `arguments` object use disqualifying optimizations by - // converting it to an array before providing it `func`. - var argsIndex = -1, argsLength = arguments.length, leftIndex = -1, leftLength = partials.length, args = Array(argsLength + leftLength); - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - var fn = this && this !== root && this instanceof wrapper ? Ctor : func; - return fn.apply(isBind ? thisArg : this, args); - } - return wrapper; - } - /** - * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. - * - * @private - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {Function} Returns the new index function. - */ - function createSortedIndex(retHighest) { - return function (array, value, iteratee, thisArg) { - var func = getCallback(iteratee); - return func === baseCallback && iteratee == null ? binaryIndex(array, value, retHighest) : binaryIndexBy(array, value, func(iteratee, thisArg, 1), retHighest); - }; - } - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to reference. - * @param {number} bitmask The bitmask of flags. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); - partials = holders = null; - } - length -= holders ? holders.length : 0; - if (bitmask & PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, holdersRight = holders; - partials = holders = null; - } - var data = isBindKey ? null : getData(func), newData = [ - func, - bitmask, - thisArg, - partials, - holders, - partialsRight, - holdersRight, - argPos, - ary, - arity - ]; - if (data) { - mergeData(newData, data); - bitmask = newData[1]; - arity = newData[9]; - } - newData[9] = arity == null ? isBindKey ? 0 : func.length : nativeMax(arity - length, 0) || 0; - if (bitmask == BIND_FLAG) { - var result = createBindWrapper(newData[0], newData[2]); - } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { - result = createPartialWrapper.apply(undefined, newData); - } else { - result = createHybridWrapper.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setter(result, newData); - } - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing arrays. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { - var index = -1, arrLength = array.length, othLength = other.length, result = true; - if (arrLength != othLength && !(isLoose && othLength > arrLength)) { - return false; - } - // Deep compare the contents, ignoring non-numeric properties. - while (result && ++index < arrLength) { - var arrValue = array[index], othValue = other[index]; - result = undefined; - if (customizer) { - result = isLoose ? customizer(othValue, arrValue, index) : customizer(arrValue, othValue, index); - } - if (result === undefined) { - // Recursively compare arrays (susceptible to call stack limits). - if (isLoose) { - var othIndex = othLength; - while (othIndex--) { - othValue = other[othIndex]; - result = arrValue && arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); - if (result) { - break; - } - } - } else { - result = arrValue && arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); - } - } - } - return !!result; - } - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} value The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag) { - switch (tag) { - case boolTag: - case dateTag: - // Coerce dates and booleans to numbers, dates to milliseconds and booleans - // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. - return +object == +other; - case errorTag: - return object.name == other.name && object.message == other.message; - case numberTag: - // Treat `NaN` vs. `NaN` as equal. - return object != +object ? other != +other : object == +other; - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings primitives and string - // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. - return object == other + ''; - } - return false; - } - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparing values. - * @param {boolean} [isLoose] Specify performing partial comparisons. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { - var objProps = keys(object), objLength = objProps.length, othProps = keys(other), othLength = othProps.length; - if (objLength != othLength && !isLoose) { - return false; - } - var skipCtor = isLoose, index = -1; - while (++index < objLength) { - var key = objProps[index], result = isLoose ? key in other : hasOwnProperty.call(other, key); - if (result) { - var objValue = object[key], othValue = other[key]; - result = undefined; - if (customizer) { - result = isLoose ? customizer(othValue, objValue, key) : customizer(objValue, othValue, key); - } - if (result === undefined) { - // Recursively compare objects (susceptible to call stack limits). - result = objValue && objValue === othValue || equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB); - } - } - if (!result) { - return false; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (!skipCtor) { - var objCtor = object.constructor, othCtor = other.constructor; - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && ('constructor' in object && 'constructor' in other) && !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) { - return false; - } - } - return true; - } - /** - * Gets the extremum value of `collection` invoking `iteratee` for each value - * in `collection` to generate the criterion by which the value is ranked. - * The `iteratee` is invoked with three arguments: (value, index, collection). - * - * @private - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {boolean} [isMin] Specify returning the minimum, instead of the - * maximum, extremum value. - * @returns {*} Returns the extremum value. - */ - function extremumBy(collection, iteratee, isMin) { - var exValue = isMin ? POSITIVE_INFINITY : NEGATIVE_INFINITY, computed = exValue, result = computed; - baseEach(collection, function (value, index, collection) { - var current = iteratee(value, index, collection); - if ((isMin ? current < computed : current > computed) || current === exValue && current === result) { - computed = current; - result = value; - } - }); - return result; - } - /** - * Gets the appropriate "callback" function. If the `_.callback` method is - * customized this function returns the custom method, otherwise it returns - * the `baseCallback` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function} Returns the chosen function or its result. - */ - function getCallback(func, thisArg, argCount) { - var result = lodash.callback || callback; - result = result === callback ? baseCallback : result; - return argCount ? result(func, thisArg, argCount) : result; - } - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function (func) { - return metaMap.get(func); - }; - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - var getFuncName = function () { - if (!support.funcNames) { - return constant(''); - } - if (constant.name == 'constant') { - return baseProperty('name'); - } - return function (func) { - var result = func.name, array = realNames[result], length = array ? array.length : 0; - while (length--) { - var data = array[length], otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - }; - }(); - /** - * Gets the appropriate "indexOf" function. If the `_.indexOf` method is - * customized this function returns the custom method, otherwise it returns - * the `baseIndexOf` function. If arguments are provided the chosen function - * is invoked with them and its result is returned. - * - * @private - * @returns {Function|number} Returns the chosen function or its result. - */ - function getIndexOf(collection, target, fromIndex) { - var result = lodash.indexOf || indexOf; - result = result === indexOf ? baseIndexOf : result; - return collection ? result(collection, target, fromIndex) : result; - } - /** - * Gets the "length" property value of `object`. - * - * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) - * that affects Safari on at least iOS 8.1-8.3 ARM64. - * - * @private - * @param {Object} object The object to query. - * @returns {*} Returns the "length" value. - */ - var getLength = baseProperty('length'); - /** - * Creates an array of the own symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = !getOwnPropertySymbols ? constant([]) : function (object) { - return getOwnPropertySymbols(toObject(object)); - }; - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} [transforms] The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, length = transforms ? transforms.length : 0; - while (++index < length) { - var data = transforms[index], size = data.size; - switch (data.type) { - case 'drop': - start += size; - break; - case 'dropRight': - end -= size; - break; - case 'take': - end = nativeMin(end, start + size); - break; - case 'takeRight': - start = nativeMax(start, end - size); - break; - } - } - return { - 'start': start, - 'end': end - }; - } - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, result = new array.constructor(length); - // Add array properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - var Ctor = object.constructor; - if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { - Ctor = Object; - } - return new Ctor(); - } - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return bufferClone(object); - case boolTag: - case dateTag: - return new Ctor(+object); - case float32Tag: - case float64Tag: - case int8Tag: - case int16Tag: - case int32Tag: - case uint8Tag: - case uint8ClampedTag: - case uint16Tag: - case uint32Tag: - var buffer = object.buffer; - return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); - case numberTag: - case stringTag: - return new Ctor(object); - case regexpTag: - var result = new Ctor(object.source, reFlags.exec(object)); - result.lastIndex = object.lastIndex; - } - return result; - } - /** - * Invokes the method at `path` on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function invokePath(object, path, args) { - if (object != null && !isKey(path, object)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - path = last(path); - } - var func = object == null ? object : object[path]; - return func == null ? undefined : func.apply(object, args); - } - /** - * Checks if `value` is array-like. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - */ - function isArrayLike(value) { - return value != null && isLength(getLength(value)); - } - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - value = +value; - length = length == null ? MAX_SAFE_INTEGER : length; - return value > -1 && value % 1 == 0 && value < length; - } - /** - * Checks if the provided arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' ? isArrayLike(object) && isIndex(index, object.length) : type == 'string' && index in object) { - var other = object[index]; - return value === value ? value === other : other !== other; - } - return false; - } - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - var type = typeof value; - if (type == 'string' && reIsPlainProp.test(value) || type == 'number') { - return true; - } - if (isArray(value)) { - return false; - } - var result = !reIsDeepProp.test(value); - return result || object != null && value in toObject(object); - } - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func); - return !!funcName && func === lodash[funcName] && funcName in LazyWrapper.prototype; - } - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength). - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - */ - function isLength(value) { - return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers required to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` - * augment function arguments, making the order in which they are executed important, - * preventing the merging of metadata. However, we make an exception for a safe - * common case where curried functions have `_.ary` and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], srcBitmask = source[1], newBitmask = bitmask | srcBitmask, isCommon = newBitmask < ARY_FLAG; - var isCombo = srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG || srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8] || srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG; - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = arrayCopy(value); - } - // Use source `ary` if it's smaller. - if (srcBitmask & ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; - return data; - } - /** - * A specialized version of `_.pick` which picks `object` properties specified - * by `props`. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property names to pick. - * @returns {Object} Returns the new object. - */ - function pickByArray(object, props) { - object = toObject(object); - var index = -1, length = props.length, result = {}; - while (++index < length) { - var key = props[index]; - if (key in object) { - result[key] = object[key]; - } - } - return result; - } - /** - * A specialized version of `_.pick` which picks `object` properties `predicate` - * returns truthy for. - * - * @private - * @param {Object} object The source object. - * @param {Function} predicate The function invoked per iteration. - * @returns {Object} Returns the new object. - */ - function pickByCallback(object, predicate) { - var result = {}; - baseForIn(object, function (value, key, object) { - if (predicate(value, key, object)) { - result[key] = value; - } - }); - return result; - } - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, length = nativeMin(indexes.length, arrLength), oldArray = arrayCopy(array); - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity function - * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = function () { - var count = 0, lastCalled = 0; - return function (key, value) { - var stamp = now(), remaining = HOT_SPAN - (stamp - lastCalled); - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return key; - } - } else { - count = 0; - } - return baseSetData(key, value); - }; - }(); - /** - * A fallback implementation of `_.isPlainObject` which checks if `value` - * is an object created by the `Object` constructor or has a `[[Prototype]]` - * of `null`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - */ - function shimIsPlainObject(value) { - var Ctor, support = lodash.support; - // Exit early for non `Object` objects. - if (!(isObjectLike(value) && objToString.call(value) == objectTag) || !hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor))) { - return false; - } - // IE < 9 iterates inherited properties before own properties. If the first - // iterated property is an object's own property then there are no inherited - // enumerable properties. - var result; - // In most environments an object's own properties are iterated before - // its inherited properties. If the last iterated property is an object's - // own property then there are no inherited enumerable properties. - baseForIn(value, function (subValue, key) { - result = key; - }); - return result === undefined || hasOwnProperty.call(value, result); - } - /** - * A fallback implementation of `Object.keys` which creates an array of the - * own enumerable property names of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function shimKeys(object) { - var props = keysIn(object), propsLength = props.length, length = propsLength && object.length, support = lodash.support; - var allowIndexes = length && isLength(length) && (isArray(object) || support.nonEnumArgs && isArguments(object)); - var index = -1, result = []; - while (++index < propsLength) { - var key = props[index]; - if (allowIndexes && isIndex(key, length) || hasOwnProperty.call(object, key)) { - result.push(key); - } - } - return result; - } - /** - * Converts `value` to an array-like object if it is not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array|Object} Returns the array-like object. - */ - function toIterable(value) { - if (value == null) { - return []; - } - if (!isArrayLike(value)) { - return values(value); - } - return isObject(value) ? value : Object(value); - } - /** - * Converts `value` to an object if it is not one. - * - * @private - * @param {*} value The value to process. - * @returns {Object} Returns the object. - */ - function toObject(value) { - return isObject(value) ? value : Object(value); - } - /** - * Converts `value` to property path array if it is not one. - * - * @private - * @param {*} value The value to process. - * @returns {Array} Returns the property path array. - */ - function toPath(value) { - if (isArray(value)) { - return value; - } - var result = []; - baseToString(value).replace(rePropName, function (match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : number || match); - }); - return result; - } - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - return wrapper instanceof LazyWrapper ? wrapper.clone() : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); - } - /** - * Creates an array of elements split into groups the length of `size`. - * If `collection` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to process. - * @param {number} [size=1] The length of each chunk. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the new array containing chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if (guard ? isIterateeCall(array, size, guard) : size == null) { - size = 1; - } else { - size = nativeMax(+size || 1, 1); - } - var index = 0, length = array ? array.length : 0, resIndex = -1, result = Array(ceil(length / size)); - while (index < length) { - result[++resIndex] = baseSlice(array, index, index += size); - } - return result; - } - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, length = array ? array.length : 0, resIndex = -1, result = []; - while (++index < length) { - var value = array[index]; - if (value) { - result[++resIndex] = value; - } - } - return result; - } - /** - * Creates an array excluding all values of the provided arrays using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The arrays of values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.difference([1, 2, 3], [4, 2]); - * // => [1, 3] - */ - var difference = restParam(function (array, values) { - return isArrayLike(array) ? baseDifference(array, baseFlatten(values, false, true)) : []; - }); - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - return baseSlice(array, n < 0 ? 0 : n); - } - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - n = length - (+n || 0); - return baseSlice(array, 0, n < 0 ? 0 : n); - } - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that match the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [1] - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); - * // => ['barney', 'fred'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); - * // => ['barney'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.dropRightWhile(users, 'active'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate, thisArg) { - return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) : []; - } - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [3] - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); - * // => ['fred', 'pebbles'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.dropWhile(users, 'active', false), 'user'); - * // => ['pebbles'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.dropWhile(users, 'active'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate, thisArg) { - return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3), true) : []; - } - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8], '*', 1, 2); - * // => [4, '*', 8] - */ - function fill(array, value, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(chr) { - * return chr.user == 'barney'; - * }); - * // => 0 - * - * // using the `_.matches` callback shorthand - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // using the `_.matchesProperty` callback shorthand - * _.findIndex(users, 'active', false); - * // => 0 - * - * // using the `_.property` callback shorthand - * _.findIndex(users, 'active'); - * // => 2 - */ - var findIndex = createFindIndex(); - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(chr) { - * return chr.user == 'pebbles'; - * }); - * // => 2 - * - * // using the `_.matches` callback shorthand - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // using the `_.matchesProperty` callback shorthand - * _.findLastIndex(users, 'active', false); - * // => 2 - * - * // using the `_.property` callback shorthand - * _.findLastIndex(users, 'active'); - * // => 0 - */ - var findLastIndex = createFindIndex(true); - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @alias head - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.first([1, 2, 3]); - * // => 1 - * - * _.first([]); - * // => undefined - */ - function first(array) { - return array ? array[0] : undefined; - } - /** - * Flattens a nested array. If `isDeep` is `true` the array is recursively - * flattened, otherwise it is only flattened a single level. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to flatten. - * @param {boolean} [isDeep] Specify a deep flatten. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, 3, [4]]]); - * // => [1, 2, 3, [4]] - * - * // using `isDeep` - * _.flatten([1, [2, 3, [4]]], true); - * // => [1, 2, 3, 4] - */ - function flatten(array, isDeep, guard) { - var length = array ? array.length : 0; - if (guard && isIterateeCall(array, isDeep, guard)) { - isDeep = false; - } - return length ? baseFlatten(array, isDeep) : []; - } - /** - * Recursively flattens a nested array. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to recursively flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, 3, [4]]]); - * // => [1, 2, 3, 4] - */ - function flattenDeep(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, true) : []; - } - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it is used as the offset - * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` - * performs a faster binary search. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=0] The index to search from or `true` - * to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // using `fromIndex` - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - * - * // performing a binary search - * _.indexOf([1, 1, 2, 2], 2, true); - * // => 2 - */ - function indexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - if (typeof fromIndex == 'number') { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; - } else if (fromIndex) { - var index = binaryIndex(array, value), other = array[index]; - if (value === value ? value === other : other !== other) { - return index; - } - return -1; - } - return baseIndexOf(array, value, fromIndex || 0); - } - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - return dropRight(array, 1); - } - /** - * Creates an array of unique values in all provided arrays using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of shared values. - * @example - * _.intersection([1, 2], [4, 2], [2, 1]); - * // => [2] - */ - function intersection() { - var args = [], argsIndex = -1, argsLength = arguments.length, caches = [], indexOf = getIndexOf(), isCommon = indexOf == baseIndexOf, result = []; - while (++argsIndex < argsLength) { - var value = arguments[argsIndex]; - if (isArrayLike(value)) { - args.push(value); - caches.push(isCommon && value.length >= 120 ? createCache(argsIndex && value) : null); - } - } - argsLength = args.length; - if (argsLength < 2) { - return result; - } - var array = args[0], index = -1, length = array ? array.length : 0, seen = caches[0]; - outer: - while (++index < length) { - value = array[index]; - if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { - argsIndex = argsLength; - while (--argsIndex) { - var cache = caches[argsIndex]; - if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value, 0)) < 0) { - continue outer; - } - } - if (seen) { - seen.push(value); - } - result.push(value); - } - } - return result; - } - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array ? array.length : 0; - return length ? array[length - 1] : undefined; - } - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to search. - * @param {*} value The value to search for. - * @param {boolean|number} [fromIndex=array.length-1] The index to search from - * or `true` to perform a binary search on a sorted array. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // using `fromIndex` - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - * - * // performing a binary search - * _.lastIndexOf([1, 1, 2, 2], 2, true); - * // => 3 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - var index = length; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; - } else if (fromIndex) { - index = binaryIndex(array, value, true) - 1; - var other = array[index]; - if (value === value ? value === other : other !== other) { - return index; - } - return -1; - } - if (value !== value) { - return indexOfNaN(array, index, true); - } - while (index--) { - if (array[index] === value) { - return index; - } - } - return -1; - } - /** - * Removes all provided values from `array` using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3, 1, 2, 3]; - * - * _.pull(array, 2, 3); - * console.log(array); - * // => [1, 1] - */ - function pull() { - var args = arguments, array = args[0]; - if (!(array && array.length)) { - return array; - } - var index = 0, indexOf = getIndexOf(), length = args.length; - while (++index < length) { - var fromIndex = 0, value = args[index]; - while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { - splice.call(array, fromIndex, 1); - } - } - return array; - } - /** - * Removes elements from `array` corresponding to the given indexes and returns - * an array of the removed elements. Indexes may be specified as an array of - * indexes or as individual arguments. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove, - * specified as individual indexes or arrays of indexes. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [5, 10, 15, 20]; - * var evens = _.pullAt(array, 1, 3); - * - * console.log(array); - * // => [5, 15] - * - * console.log(evens); - * // => [10, 20] - */ - var pullAt = restParam(function (array, indexes) { - indexes = baseFlatten(indexes); - var result = baseAt(array, indexes); - basePullAt(array, indexes.sort(baseCompareAscending)); - return result; - }); - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * **Note:** Unlike `_.filter`, this method mutates `array`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to modify. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate, thisArg) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, indexes = [], length = array.length; - predicate = getCallback(predicate, thisArg, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @alias tail - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.rest([1, 2, 3]); - * // => [2, 3] - */ - function rest(array) { - return drop(array, 1); - } - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of `Array#slice` to support node - * lists in IE < 9 and to ensure dense arrays are returned. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - return baseSlice(array, start, end); - } - /** - * Uses a binary search to determine the lowest index at which `value` should - * be inserted into `array` in order to maintain its sort order. If an iteratee - * function is provided it is invoked for `value` and each element of `array` - * to compute their sort ranking. The iteratee is bound to `thisArg` and - * invoked with one argument; (value). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - * - * _.sortedIndex([4, 4, 5, 5], 5); - * // => 2 - * - * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; - * - * // using an iteratee function - * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { - * return this.data[word]; - * }, dict); - * // => 1 - * - * // using the `_.property` callback shorthand - * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); - * // => 1 - */ - var sortedIndex = createSortedIndex(); - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 4, 5, 5], 5); - * // => 4 - */ - var sortedLastIndex = createSortedIndex(true); - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - return baseSlice(array, 0, n < 0 ? 0 : n); - } - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (guard ? isIterateeCall(array, n, guard) : n == null) { - n = 1; - } - n = length - (+n || 0); - return baseSlice(array, n < 0 ? 0 : n); - } - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is bound to `thisArg` - * and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRightWhile([1, 2, 3], function(n) { - * return n > 1; - * }); - * // => [2, 3] - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); - * // => ['pebbles'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); - * // => ['fred', 'pebbles'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.takeRightWhile(users, 'active'), 'user'); - * // => [] - */ - function takeRightWhile(array, predicate, thisArg) { - return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) : []; - } - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is bound to - * `thisArg` and invoked with three arguments: (value, index, array). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to query. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeWhile([1, 2, 3], function(n) { - * return n < 3; - * }); - * // => [1, 2] - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false}, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.takeWhile(users, 'active', false), 'user'); - * // => ['barney', 'fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.takeWhile(users, 'active'), 'user'); - * // => [] - */ - function takeWhile(array, predicate, thisArg) { - return array && array.length ? baseWhile(array, getCallback(predicate, thisArg, 3)) : []; - } - /** - * Creates an array of unique values, in order, of the provided arrays using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([1, 2], [4, 2], [2, 1]); - * // => [1, 2, 4] - */ - var union = restParam(function (arrays) { - return baseUniq(baseFlatten(arrays, false, true)); - }); - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons, in which only the first occurence of each element - * is kept. Providing `true` for `isSorted` performs a faster search algorithm - * for sorted arrays. If an iteratee function is provided it is invoked for - * each element in the array to generate the criterion by which uniqueness - * is computed. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index, array). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias unique - * @category Array - * @param {Array} array The array to inspect. - * @param {boolean} [isSorted] Specify the array is sorted. - * @param {Function|Object|string} [iteratee] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new duplicate-value-free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - * - * // using `isSorted` - * _.uniq([1, 1, 2], true); - * // => [1, 2] - * - * // using an iteratee function - * _.uniq([1, 2.5, 1.5, 2], function(n) { - * return this.floor(n); - * }, Math); - * // => [1, 2.5] - * - * // using the `_.property` callback shorthand - * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniq(array, isSorted, iteratee, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (isSorted != null && typeof isSorted != 'boolean') { - thisArg = iteratee; - iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted; - isSorted = false; - } - var func = getCallback(); - if (!(func === baseCallback && iteratee == null)) { - iteratee = func(iteratee, thisArg, 3); - } - return isSorted && getIndexOf() == baseIndexOf ? sortedUniq(array, iteratee) : baseUniq(array, iteratee); - } - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - * - * _.unzip(zipped); - * // => [['fred', 'barney'], [30, 40], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var index = -1, length = 0; - array = arrayFilter(array, function (group) { - if (isArrayLike(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - var result = Array(length); - while (++index < length) { - result[index] = arrayMap(array, baseProperty(index)); - } - return result; - } - /** - * This method is like `_.unzip` except that it accepts an iteratee to specify - * how regrouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee] The function to combine regrouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee, thisArg) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - iteratee = bindCallback(iteratee, thisArg, 4); - return arrayMap(result, function (group) { - return arrayReduce(group, iteratee, undefined, true); - }); - } - /** - * Creates an array excluding all provided values using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @category Array - * @param {Array} array The array to filter. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.without([1, 2, 1, 3], 1, 2); - * // => [3] - */ - var without = restParam(function (array, values) { - return isArrayLike(array) ? baseDifference(array, values) : []; - }); - /** - * Creates an array that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the provided arrays. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of values. - * @example - * - * _.xor([1, 2], [4, 2]); - * // => [1, 4] - */ - function xor() { - var index = -1, length = arguments.length; - while (++index < length) { - var array = arguments[index]; - if (isArrayLike(array)) { - var result = result ? baseDifference(result, array).concat(baseDifference(array, result)) : array; - } - } - return result ? baseUniq(result) : []; - } - /** - * Creates an array of grouped elements, the first of which contains the first - * elements of the given arrays, the second of which contains the second elements - * of the given arrays, and so on. - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['fred', 'barney'], [30, 40], [true, false]); - * // => [['fred', 30, true], ['barney', 40, false]] - */ - var zip = restParam(unzip); - /** - * The inverse of `_.pairs`; this method returns an object composed from arrays - * of property names and values. Provide either a single two dimensional array, - * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names - * and one of corresponding values. - * - * @static - * @memberOf _ - * @alias object - * @category Array - * @param {Array} props The property names. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject([['fred', 30], ['barney', 40]]); - * // => { 'fred': 30, 'barney': 40 } - * - * _.zipObject(['fred', 'barney'], [30, 40]); - * // => { 'fred': 30, 'barney': 40 } - */ - function zipObject(props, values) { - var index = -1, length = props ? props.length : 0, result = {}; - if (length && !values && !isArray(props[0])) { - values = []; - } - while (++index < length) { - var key = props[index]; - if (values) { - result[key] = values[index]; - } else if (key) { - result[key[0]] = key[1]; - } - } - return result; - } - /** - * This method is like `_.zip` except that it accepts an iteratee to specify - * how grouped values should be combined. The `iteratee` is bound to `thisArg` - * and invoked with four arguments: (accumulator, value, index, group). - * - * @static - * @memberOf _ - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee] The function to combine grouped values. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], _.add); - * // => [111, 222] - */ - var zipWith = restParam(function (arrays) { - var length = arrays.length, iteratee = arrays[length - 2], thisArg = arrays[length - 1]; - if (length > 2 && typeof iteratee == 'function') { - length -= 2; - } else { - iteratee = length > 1 && typeof thisArg == 'function' ? (--length, thisArg) : undefined; - thisArg = undefined; - } - arrays.length = length; - return unzipWith(arrays, iteratee, thisArg); - }); - /** - * Creates a `lodash` object that wraps `value` with explicit method - * chaining enabled. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _.chain(users) - * .sortBy('age') - * .map(function(chr) { - * return chr.user + ' is ' + chr.age; - * }) - * .first() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - /** - * This method invokes `interceptor` and returns `value`. The interceptor is - * bound to `thisArg` and invoked with one argument; (value). The purpose of - * this method is to "tap into" a method chain in order to perform operations - * on intermediate results within the chain. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor, thisArg) { - interceptor.call(thisArg, value); - return value; - } - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * - * @static - * @memberOf _ - * @category Chain - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @param {*} [thisArg] The `this` binding of `interceptor`. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor, thisArg) { - return interceptor.call(thisArg, value); - } - /** - * Enables explicit method chaining on the wrapper object. - * - * @name chain - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // without explicit chaining - * _(users).first(); - * // => { 'user': 'barney', 'age': 36 } - * - * // with explicit chaining - * _(users).chain() - * .first() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - /** - * Executes the chained sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapper = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapper = wrapper.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapper.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } - /** - * Creates a clone of the chained sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapper = _(array).map(function(value) { - * return Math.pow(value, 2); - * }); - * - * var other = [3, 4]; - * var otherWrapper = wrapper.plant(other); - * - * otherWrapper.value(); - * // => [9, 16] - * - * wrapper.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, parent = this; - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } - /** - * Reverses the wrapped array so the first element becomes the last, the - * second element becomes the second to last, and so on. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @category Chain - * @returns {Object} Returns the new reversed `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - if (value instanceof LazyWrapper) { - if (this.__actions__.length) { - value = new LazyWrapper(this); - } - return new LodashWrapper(value.reverse(), this.__chain__); - } - return this.thru(function (value) { - return value.reverse(); - }); - } - /** - * Produces the result of coercing the unwrapped value to a string. - * - * @name toString - * @memberOf _ - * @category Chain - * @returns {string} Returns the coerced string value. - * @example - * - * _([1, 2, 3]).toString(); - * // => '1,2,3' - */ - function wrapperToString() { - return this.value() + ''; - } - /** - * Executes the chained sequence to extract the unwrapped value. - * - * @name value - * @memberOf _ - * @alias run, toJSON, valueOf - * @category Chain - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - /** - * Creates an array of elements corresponding to the given keys, or indexes, - * of `collection`. Keys may be specified as individual arguments or as arrays - * of keys. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(number|number[]|string|string[])} [props] The property names - * or indexes of elements to pick, specified individually or in arrays. - * @returns {Array} Returns the new array of picked elements. - * @example - * - * _.at(['a', 'b', 'c'], [0, 2]); - * // => ['a', 'c'] - * - * _.at(['barney', 'fred', 'pebbles'], 0, 2); - * // => ['barney', 'pebbles'] - */ - var at = restParam(function (collection, props) { - return baseAt(collection, baseFlatten(props)); - }); - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is the number of times the key was returned by `iteratee`. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return Math.floor(n); - * }); - * // => { '4': 1, '6': 2 } - * - * _.countBy([4.3, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': 1, '6': 2 } - * - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function (result, value, key) { - hasOwnProperty.call(result, key) ? ++result[key] : result[key] = 1; - }); - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * The predicate is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias all - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // using the `_.matchesProperty` callback shorthand - * _.every(users, 'active', false); - * // => true - * - * // using the `_.property` callback shorthand - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = null; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); - } - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias select - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new filtered array. - * @example - * - * _.filter([4, 5, 6], function(n) { - * return n % 2 == 0; - * }); - * // => [4, 6] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.filter(users, 'active', false), 'user'); - * // => ['fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.filter(users, 'active'), 'user'); - * // => ['barney'] - */ - function filter(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, predicate); - } - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is bound to `thisArg` and - * invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias detect - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.result(_.find(users, function(chr) { - * return chr.age < 40; - * }), 'user'); - * // => 'barney' - * - * // using the `_.matches` callback shorthand - * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); - * // => 'pebbles' - * - * // using the `_.matchesProperty` callback shorthand - * _.result(_.find(users, 'active', false), 'user'); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.result(_.find(users, 'active'), 'user'); - * // => 'barney' - */ - var find = createFind(baseEach); - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(baseEachRight, true); - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning the first element that has equivalent property - * values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); - * // => 'barney' - * - * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); - * // => 'fred' - */ - function findWhere(collection, source) { - return find(collection, baseMatches(source)); - } - /** - * Iterates over elements of `collection` invoking `iteratee` for each element. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). Iteratee functions may exit iteration early - * by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" property - * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` - * may be used for object iteration. - * - * @static - * @memberOf _ - * @alias each - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2]).forEach(function(n) { - * console.log(n); - * }).value(); - * // => logs each value from left to right and returns the array - * - * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { - * console.log(n, key); - * }); - * // => logs each value-key pair and returns the object (iteration order is not guaranteed) - */ - var forEach = createForEach(arrayEach, baseEach); - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @alias eachRight - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array|Object|string} Returns `collection`. - * @example - * - * _([1, 2]).forEachRight(function(n) { - * console.log(n); - * }).value(); - * // => logs each value from right to left and returns the array - */ - var forEachRight = createForEach(arrayEachRight, baseEachRight); - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is an array of the elements responsible for generating the key. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return Math.floor(n); - * }); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * _.groupBy([4.2, 6.1, 6.4], function(n) { - * return this.floor(n); - * }, Math); - * // => { '4': [4.2], '6': [6.1, 6.4] } - * - * // using the `_.property` callback shorthand - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function (result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - result[key] = [value]; - } - }); - /** - * Checks if `value` is in `collection` using - * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it is used as the offset - * from the end of `collection`. - * - * @static - * @memberOf _ - * @alias contains, include - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {*} target The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. - * @returns {boolean} Returns `true` if a matching element is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); - * // => true - * - * _.includes('pebbles', 'eb'); - * // => true - */ - function includes(collection, target, fromIndex, guard) { - var length = collection ? getLength(collection) : 0; - if (!isLength(length)) { - collection = values(collection); - length = collection.length; - } - if (!length) { - return false; - } - if (typeof fromIndex != 'number' || guard && isIterateeCall(target, fromIndex, guard)) { - fromIndex = 0; - } else { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex || 0; - } - return typeof collection == 'string' || !isArray(collection) && isString(collection) ? fromIndex < length && collection.indexOf(target, fromIndex) > -1 : getIndexOf(collection, target, fromIndex) > -1; - } - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` through `iteratee`. The corresponding value - * of each key is the last element responsible for generating the key. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var keyData = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.indexBy(keyData, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return String.fromCharCode(object.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.indexBy(keyData, function(object) { - * return this.fromCharCode(object.code); - * }, String); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - */ - var indexBy = createAggregator(function (result, value, key) { - result[key] = value; - }); - /** - * Invokes the method at `path` on each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `methodName` is a function it is - * invoked for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invoke([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invoke = restParam(function (collection, path, args) { - var index = -1, isFunc = typeof path == 'function', isProp = isKey(path), result = isArrayLike(collection) ? Array(collection.length) : []; - baseEach(collection, function (value) { - var func = isFunc ? path : isProp && value != null && value[path]; - result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); - }); - return result; - }); - /** - * Creates an array of values by running each element in `collection` through - * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three - * arguments: (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * Many lodash methods are guarded to work as interatees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, - * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, - * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, - * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, - * `sum`, `uniq`, and `words` - * - * @static - * @memberOf _ - * @alias collect - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new mapped array. - * @example - * - * function timesThree(n) { - * return n * 3; - * } - * - * _.map([1, 2], timesThree); - * // => [3, 6] - * - * _.map({ 'a': 1, 'b': 2 }, timesThree); - * // => [3, 6] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // using the `_.property` callback shorthand - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee, thisArg) { - var func = isArray(collection) ? arrayMap : baseMap; - iteratee = getCallback(iteratee, thisArg, 3); - return func(collection, iteratee); - } - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, while the second of which - * contains elements `predicate` returns falsey for. The predicate is bound - * to `thisArg` and invoked with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * _.partition([1, 2, 3], function(n) { - * return n % 2; - * }); - * // => [[1, 3], [2]] - * - * _.partition([1.2, 2.3, 3.4], function(n) { - * return this.floor(n) % 2; - * }, Math); - * // => [[1.2, 3.4], [2.3]] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * var mapper = function(array) { - * return _.pluck(array, 'user'); - * }; - * - * // using the `_.matches` callback shorthand - * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); - * // => [['pebbles'], ['barney', 'fred']] - * - * // using the `_.matchesProperty` callback shorthand - * _.map(_.partition(users, 'active', false), mapper); - * // => [['barney', 'pebbles'], ['fred']] - * - * // using the `_.property` callback shorthand - * _.map(_.partition(users, 'active'), mapper); - * // => [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function (result, value, key) { - result[key ? 0 : 1].push(value); - }, function () { - return [ - [], - [] - ]; - }); - /** - * Gets the property value of `path` from all elements in `collection`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Array|string} path The path of the property to pluck. - * @returns {Array} Returns the property values. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * _.pluck(users, 'user'); - * // => ['barney', 'fred'] - * - * var userIndex = _.indexBy(users, 'user'); - * _.pluck(userIndex, 'age'); - * // => [36, 40] (iteration order is not guaranteed) - */ - function pluck(collection, path) { - return map(collection, property(path)); - } - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` through `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not provided the first element of `collection` is used as the initial - * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as interatees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `includes`, `merge`, `sortByAll`, and `sortByOrder` - * - * @static - * @memberOf _ - * @alias foldl, inject - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * _.reduce([1, 2], function(total, n) { - * return total + n; - * }); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { - * result[key] = n * 3; - * return result; - * }, {}); - * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) - */ - var reduce = createReduce(arrayReduce, baseEach); - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @alias foldr - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - var reduceRight = createReduce(arrayReduceRight, baseEachRight); - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Array} Returns the new filtered array. - * @example - * - * _.reject([1, 2, 3, 4], function(n) { - * return n % 2 == 0; - * }); - * // => [1, 3] - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * // using the `_.matches` callback shorthand - * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); - * // => ['barney'] - * - * // using the `_.matchesProperty` callback shorthand - * _.pluck(_.reject(users, 'active', false), 'user'); - * // => ['fred'] - * - * // using the `_.property` callback shorthand - * _.pluck(_.reject(users, 'active'), 'user'); - * // => ['barney'] - */ - function reject(collection, predicate, thisArg) { - var func = isArray(collection) ? arrayFilter : baseFilter; - predicate = getCallback(predicate, thisArg, 3); - return func(collection, function (value, index, collection) { - return !predicate(value, index, collection); - }); - } - /** - * Gets a random element or `n` random elements from a collection. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to sample. - * @param {number} [n] The number of elements to sample. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {*} Returns the random sample(s). - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - * - * _.sample([1, 2, 3, 4], 2); - * // => [3, 1] - */ - function sample(collection, n, guard) { - if (guard ? isIterateeCall(collection, n, guard) : n == null) { - collection = toIterable(collection); - var length = collection.length; - return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; - } - var result = shuffle(collection); - result.length = nativeMin(n < 0 ? 0 : +n || 0, result.length); - return result; - } - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - collection = toIterable(collection); - var index = -1, length = collection.length, result = Array(length); - while (++index < length) { - var rand = baseRandom(0, index); - if (index != rand) { - result[index] = result[rand]; - } - result[rand] = collection[index]; - } - return result; - } - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable properties for objects. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the size of `collection`. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - var length = collection ? getLength(collection) : 0; - return isLength(length) ? length : keys(collection).length; - } - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * The function returns as soon as it finds a passing value and does not iterate - * over the entire collection. The predicate is bound to `thisArg` and invoked - * with three arguments: (value, index|key, collection). - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @alias any - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // using the `_.matches` callback shorthand - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // using the `_.matchesProperty` callback shorthand - * _.some(users, 'active', false); - * // => true - * - * // using the `_.property` callback shorthand - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, thisArg) { - var func = isArray(collection) ? arraySome : baseSome; - if (thisArg && isIterateeCall(collection, predicate, thisArg)) { - predicate = null; - } - if (typeof predicate != 'function' || thisArg !== undefined) { - predicate = getCallback(predicate, thisArg, 3); - } - return func(collection, predicate); - } - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection through `iteratee`. This method performs - * a stable sort, that is, it preserves the original sort order of equal elements. - * The `iteratee` is bound to `thisArg` and invoked with three arguments: - * (value, index|key, collection). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Array} Returns the new sorted array. - * @example - * - * _.sortBy([1, 2, 3], function(n) { - * return Math.sin(n); - * }); - * // => [3, 1, 2] - * - * _.sortBy([1, 2, 3], function(n) { - * return this.sin(n); - * }, Math); - * // => [3, 1, 2] - * - * var users = [ - * { 'user': 'fred' }, - * { 'user': 'pebbles' }, - * { 'user': 'barney' } - * ]; - * - * // using the `_.property` callback shorthand - * _.pluck(_.sortBy(users, 'user'), 'user'); - * // => ['barney', 'fred', 'pebbles'] - */ - function sortBy(collection, iteratee, thisArg) { - if (collection == null) { - return []; - } - if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { - iteratee = null; - } - var index = -1; - iteratee = getCallback(iteratee, thisArg, 3); - var result = baseMap(collection, function (value, key, collection) { - return { - 'criteria': iteratee(value, key, collection), - 'index': ++index, - 'value': value - }; - }); - return baseSortBy(result, compareAscending); - } - /** - * This method is like `_.sortBy` except that it can sort by multiple iteratees - * or property names. - * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees - * The iteratees to sort by, specified as individual values or arrays of values. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 42 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.map(_.sortByAll(users, ['user', 'age']), _.values); - * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] - * - * _.map(_.sortByAll(users, 'user', function(chr) { - * return Math.floor(chr.age / 10); - * }), _.values); - * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] - */ - var sortByAll = restParam(function (collection, iteratees) { - if (collection == null) { - return []; - } - var guard = iteratees[2]; - if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { - iteratees.length = 1; - } - return baseSortByOrder(collection, baseFlatten(iteratees), []); - }); - /** - * This method is like `_.sortByAll` except that it allows specifying the - * sort orders of the iteratees to sort by. A truthy value in `orders` will - * sort the corresponding property name in ascending order while a falsey - * value will sort it in descending order. - * - * If a property name is provided for an iteratee the created `_.property` - * style callback returns the property value of the given element. - * - * If an object is provided for an iteratee the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {boolean[]} orders The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 42 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // sort by `user` in ascending order and by `age` in descending order - * _.map(_.sortByOrder(users, ['user', 'age'], [true, false]), _.values); - * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] - */ - function sortByOrder(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (guard && isIterateeCall(iteratees, orders, guard)) { - orders = null; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseSortByOrder(collection, iteratees, orders); - } - /** - * Performs a deep comparison between each element in `collection` and the - * source object, returning an array of all elements that have equivalent - * property values. - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. For comparing a single - * own or inherited property value see `_.matchesProperty`. - * - * @static - * @memberOf _ - * @category Collection - * @param {Array|Object|string} collection The collection to search. - * @param {Object} source The object of property values to match. - * @returns {Array} Returns the new filtered array. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, - * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } - * ]; - * - * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); - * // => ['barney'] - * - * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); - * // => ['fred'] - */ - function where(collection, source) { - return filter(collection, baseMatches(source)); - } - /** - * Gets the number of milliseconds that have elapsed since the Unix epoch - * (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @category Date - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => logs the number of milliseconds it took for the deferred function to be invoked - */ - var now = nativeNow || function () { - return new Date().getTime(); - }; - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it is called `n` or more times. - * - * @static - * @memberOf _ - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => logs 'done saving!' after the two async saves have completed - */ - function after(n, func) { - if (typeof func != 'function') { - if (typeof n == 'function') { - var temp = n; - n = func; - func = temp; - } else { - throw new TypeError(FUNC_ERROR_TEXT); - } - } - n = nativeIsFinite(n = +n) ? n : 0; - return function () { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - /** - * Creates a function that accepts up to `n` arguments ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to cap arguments for. - * @param {number} [n=func.length] The arity cap. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - if (guard && isIterateeCall(func, n, guard)) { - n = null; - } - n = func && n == null ? func.length : nativeMax(+n || 0, 0); - return createWrapper(func, ARY_FLAG, null, null, null, null, n); - } - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it is called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery('#add').on('click', _.before(5, addContactToList)); - * // => allows adding up to 4 contacts to the list - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - if (typeof n == 'function') { - var temp = n; - n = func; - func = temp; - } else { - throw new TypeError(FUNC_ERROR_TEXT); - } - } - return function () { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = null; - } - return result; - }; - } - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and prepends any additional `_.bind` arguments to those provided to the - * bound function. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind` this method does not set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var greet = function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * }; - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // using placeholders - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = restParam(function (func, thisArg, partials) { - var bitmask = BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, bind.placeholder); - bitmask |= PARTIAL_FLAG; - } - return createWrapper(func, bitmask, thisArg, partials, holders); - }); - /** - * Binds methods of an object to the object itself, overwriting the existing - * method. Method names may be specified as individual arguments or as arrays - * of method names. If no method names are provided all enumerable function - * properties, own and inherited, of `object` are bound. - * - * **Note:** This method does not set the "length" property of bound functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Object} object The object to bind and assign the bound methods to. - * @param {...(string|string[])} [methodNames] The object method names to bind, - * specified as individual method names or arrays of method names. - * @returns {Object} Returns `object`. - * @example - * - * var view = { - * 'label': 'docs', - * 'onClick': function() { - * console.log('clicked ' + this.label); - * } - * }; - * - * _.bindAll(view); - * jQuery('#docs').on('click', view.onClick); - * // => logs 'clicked docs' when the element is clicked - */ - var bindAll = restParam(function (object, methodNames) { - methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); - var index = -1, length = methodNames.length; - while (++index < length) { - var key = methodNames[index]; - object[key] = createWrapper(object[key], BIND_FLAG, object); - } - return object; - }); - /** - * Creates a function that invokes the method at `object[key]` and prepends - * any additional `_.bindKey` arguments to those provided to the bound function. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. - * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @category Function - * @param {Object} object The object the method belongs to. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // using placeholders - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = restParam(function (object, key, partials) { - var bitmask = BIND_FLAG | BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, bindKey.placeholder); - bitmask |= PARTIAL_FLAG; - } - return createWrapper(key, bitmask, object, partials, holders); - }); - /** - * Creates a function that accepts one or more arguments of `func` that when - * called either invokes `func` returning its result, if all `func` arguments - * have been provided, or returns a function that accepts one or more of the - * remaining `func` arguments, and so on. The arity of `func` may be specified - * if `func.length` is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method does not set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // using placeholders - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - var curry = createCurry(CURRY_FLAG); - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method does not set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // using placeholders - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - var curryRight = createCurry(CURRY_RIGHT_FLAG); - /** - * Creates a function that delays invoking `func` until after `wait` milliseconds - * have elapsed since the last time it was invoked. The created function comes - * with a `cancel` method to cancel delayed invocations. Provide an options - * object to indicate that `func` should be invoked on the leading and/or - * trailing edge of the `wait` timeout. Subsequent calls to the debounced - * function return the result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked - * on the trailing edge of the timeout only if the the debounced function is - * invoked more than once during the `wait` timeout. - * - * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=false] Specify invoking on the leading - * edge of the timeout. - * @param {number} [options.maxWait] The maximum time `func` is allowed to be - * delayed before it is invoked. - * @param {boolean} [options.trailing=true] Specify invoking on the trailing - * edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // avoid costly calculations while the window size is in flux - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // invoke `sendMail` when the click event is fired, debouncing subsequent calls - * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // ensure `batchLog` is invoked once after 1 second of debounced calls - * var source = new EventSource('/stream'); - * jQuery(source).on('message', _.debounce(batchLog, 250, { - * 'maxWait': 1000 - * })); - * - * // cancel a debounced call - * var todoChanges = _.debounce(batchLog, 1000); - * Object.observe(models.todo, todoChanges); - * - * Object.observe(models, function(changes) { - * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { - * todoChanges.cancel(); - * } - * }, ['delete']); - * - * // ...at some point `models.todo` is changed - * models.todo.completed = true; - * - * // ...before 1 second has passed `models.todo` is deleted - * // which cancels the debounced `todoChanges` call - * delete models.todo; - */ - function debounce(func, wait, options) { - var args, maxTimeoutId, result, stamp, thisArg, timeoutId, trailingCall, lastCalled = 0, maxWait = false, trailing = true; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = wait < 0 ? 0 : +wait || 0; - if (options === true) { - var leading = true; - trailing = false; - } else if (isObject(options)) { - leading = options.leading; - maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); - trailing = 'trailing' in options ? options.trailing : trailing; - } - function cancel() { - if (timeoutId) { - clearTimeout(timeoutId); - } - if (maxTimeoutId) { - clearTimeout(maxTimeoutId); - } - maxTimeoutId = timeoutId = trailingCall = undefined; - } - function delayed() { - var remaining = wait - (now() - stamp); - if (remaining <= 0 || remaining > wait) { - if (maxTimeoutId) { - clearTimeout(maxTimeoutId); - } - var isCalled = trailingCall; - maxTimeoutId = timeoutId = trailingCall = undefined; - if (isCalled) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - } - } else { - timeoutId = setTimeout(delayed, remaining); - } - } - function maxDelayed() { - if (timeoutId) { - clearTimeout(timeoutId); - } - maxTimeoutId = timeoutId = trailingCall = undefined; - if (trailing || maxWait !== wait) { - lastCalled = now(); - result = func.apply(thisArg, args); - if (!timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - } - } - function debounced() { - args = arguments; - stamp = now(); - thisArg = this; - trailingCall = trailing && (timeoutId || !leading); - if (maxWait === false) { - var leadingCall = leading && !timeoutId; - } else { - if (!maxTimeoutId && !leading) { - lastCalled = stamp; - } - var remaining = maxWait - (stamp - lastCalled), isCalled = remaining <= 0 || remaining > maxWait; - if (isCalled) { - if (maxTimeoutId) { - maxTimeoutId = clearTimeout(maxTimeoutId); - } - lastCalled = stamp; - result = func.apply(thisArg, args); - } else if (!maxTimeoutId) { - maxTimeoutId = setTimeout(maxDelayed, remaining); - } - } - if (isCalled && timeoutId) { - timeoutId = clearTimeout(timeoutId); - } else if (!timeoutId && wait !== maxWait) { - timeoutId = setTimeout(delayed, wait); - } - if (leadingCall) { - isCalled = true; - result = func.apply(thisArg, args); - } - if (isCalled && !timeoutId && !maxTimeoutId) { - args = thisArg = null; - } - return result; - } - debounced.cancel = cancel; - return debounced; - } - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it is invoked. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // logs 'deferred' after one or more milliseconds - */ - var defer = restParam(function (func, args) { - return baseDelay(func, 1, args); - }); - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it is invoked. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke the function with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => logs 'later' after one second - */ - var delay = restParam(function (func, wait, args) { - return baseDelay(func, wait, args); - }); - /** - * Creates a function that returns the result of invoking the provided - * functions with the `this` binding of the created function, where each - * successive invocation is supplied the return value of the previous. - * - * @static - * @memberOf _ - * @category Function - * @param {...Function} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var addSquare = _.flow(_.add, square); - * addSquare(1, 2); - * // => 9 - */ - var flow = createFlow(); - /** - * This method is like `_.flow` except that it creates a function that - * invokes the provided functions from right to left. - * - * @static - * @memberOf _ - * @alias backflow, compose - * @category Function - * @param {...Function} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var addSquare = _.flowRight(square, _.add); - * addSquare(1, 2); - * // => 9 - */ - var flowRight = createFlow(true); - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is coerced to a string and used as the - * cache key. The `func` is invoked with the `this` binding of the memoized - * function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the [`Map`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-properties-of-the-map-prototype-object) - * method interface of `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoizing function. - * @example - * - * var upperCase = _.memoize(function(string) { - * return string.toUpperCase(); - * }); - * - * upperCase('fred'); - * // => 'FRED' - * - * // modifying the result cache - * upperCase.cache.set('fred', 'BARNEY'); - * upperCase('fred'); - * // => 'BARNEY' - * - * // replacing `_.memoize.Cache` - * var object = { 'user': 'fred' }; - * var other = { 'user': 'barney' }; - * var identity = _.memoize(_.identity); - * - * identity(object); - * // => { 'user': 'fred' } - * identity(other); - * // => { 'user': 'fred' } - * - * _.memoize.Cache = WeakMap; - * var identity = _.memoize(_.identity); - * - * identity(object); - * // => { 'user': 'fred' } - * identity(other); - * // => { 'user': 'barney' } - */ - function memoize(func, resolver) { - if (typeof func != 'function' || resolver && typeof resolver != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function () { - var args = arguments, cache = memoized.cache, key = resolver ? resolver.apply(this, args) : args[0]; - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - cache.set(key, result); - return result; - }; - memoized.cache = new memoize.Cache(); - return memoized; - } - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function () { - return !predicate.apply(this, arguments); - }; - } - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first call. The `func` is invoked - * with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // `initialize` invokes `createApplication` once - */ - function once(func) { - return before(2, func); - } - /** - * Creates a function that invokes `func` with `partial` arguments prepended - * to those provided to the new function. This method is like `_.bind` except - * it does **not** alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method does not set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { - * return greeting + ' ' + name; - * }; - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // using placeholders - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = createPartial(PARTIAL_FLAG); - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to those provided to the new function. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method does not set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * var greet = function(greeting, name) { - * return greeting + ' ' + name; - * }; - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // using placeholders - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = createPartial(PARTIAL_RIGHT_FLAG); - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified indexes where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes, - * specified as individual indexes or arrays of indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, 2, 0, 1); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - * - * var map = _.rearg(_.map, [1, 0]); - * map(function(n) { - * return n * 3; - * }, [1, 2, 3]); - * // => [3, 6, 9] - */ - var rearg = restParam(function (func, indexes) { - return createWrapper(func, REARG_FLAG, null, null, null, baseFlatten(indexes)); - }); - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as an array. - * - * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters). - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.restParam(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function restParam(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = nativeMax(start === undefined ? func.length - 1 : +start || 0, 0); - return function () { - var args = arguments, index = -1, length = nativeMax(args.length - start, 0), rest = Array(length); - while (++index < length) { - rest[index] = args[start + index]; - } - switch (start) { - case 0: - return func.call(this, rest); - case 1: - return func.call(this, args[0], rest); - case 2: - return func.call(this, args[0], args[1], rest); - } - var otherArgs = Array(start + 1); - index = -1; - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = rest; - return func.apply(this, otherArgs); - }; - } - /** - * Creates a function that invokes `func` with the `this` binding of the created - * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3). - * - * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator). - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to spread arguments over. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * // with a Promise - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function (array) { - return func.apply(this, array); - }; - } - /** - * Creates a function that only invokes `func` at most once per every `wait` - * milliseconds. The created function comes with a `cancel` method to cancel - * delayed invocations. Provide an options object to indicate that `func` - * should be invoked on the leading and/or trailing edge of the `wait` timeout. - * Subsequent calls to the throttled function return the result of the last - * `func` call. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked - * on the trailing edge of the timeout only if the the throttled function is - * invoked more than once during the `wait` timeout. - * - * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options] The options object. - * @param {boolean} [options.leading=true] Specify invoking on the leading - * edge of the timeout. - * @param {boolean} [options.trailing=true] Specify invoking on the trailing - * edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // avoid excessively updating the position while scrolling - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes - * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { - * 'trailing': false - * })); - * - * // cancel a trailing throttled call - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, trailing = true; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (options === false) { - leading = false; - } else if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - debounceOptions.leading = leading; - debounceOptions.maxWait = +wait; - debounceOptions.trailing = trailing; - return debounce(func, wait, debounceOptions); - } - /** - * Creates a function that provides `value` to the wrapper function as its - * first argument. Any additional arguments provided to the function are - * appended to those provided to the wrapper function. The wrapper is invoked - * with the `this` binding of the created function. - * - * @static - * @memberOf _ - * @category Function - * @param {*} value The value to wrap. - * @param {Function} wrapper The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

' + func(text) + '

'; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

fred, barney, & pebbles

' - */ - function wrap(value, wrapper) { - wrapper = wrapper == null ? identity : wrapper; - return createWrapper(wrapper, PARTIAL_FLAG, null, [value], []); - } - /** - * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, - * otherwise they are assigned by reference. If `customizer` is provided it is - * invoked to produce the cloned values. If `customizer` returns `undefined` - * cloning is handled by the method instead. The `customizer` is bound to - * `thisArg` and invoked with two argument; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {*} Returns the cloned value. - * @example - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * var shallow = _.clone(users); - * shallow[0] === users[0]; - * // => true - * - * var deep = _.clone(users, true); - * deep[0] === users[0]; - * // => false - * - * // using a customizer callback - * var el = _.clone(document.body, function(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * }); - * - * el === document.body - * // => false - * el.nodeName - * // => BODY - * el.childNodes.length; - * // => 0 - */ - function clone(value, isDeep, customizer, thisArg) { - if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { - isDeep = false; - } else if (typeof isDeep == 'function') { - thisArg = customizer; - customizer = isDeep; - isDeep = false; - } - customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); - return baseClone(value, isDeep, customizer); - } - /** - * Creates a deep clone of `value`. If `customizer` is provided it is invoked - * to produce the cloned values. If `customizer` returns `undefined` cloning - * is handled by the method instead. The `customizer` is bound to `thisArg` - * and invoked with two argument; (value [, index|key, object]). - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). - * The enumerable properties of `arguments` objects and objects created by - * constructors other than `Object` are cloned to plain `Object` objects. An - * empty object is returned for uncloneable values such as functions, DOM nodes, - * Maps, Sets, and WeakMaps. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to deep clone. - * @param {Function} [customizer] The function to customize cloning values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {*} Returns the deep cloned value. - * @example - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * var deep = _.cloneDeep(users); - * deep[0] === users[0]; - * // => false - * - * // using a customizer callback - * var el = _.cloneDeep(document.body, function(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * }); - * - * el === document.body - * // => false - * el.nodeName - * // => BODY - * el.childNodes.length; - * // => 20 - */ - function cloneDeep(value, customizer, thisArg) { - customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); - return baseClone(value, true, customizer); - } - /** - * Checks if `value` is classified as an `arguments` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - function isArguments(value) { - return isObjectLike(value) && isArrayLike(value) && objToString.call(value) == argsTag; - } - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(function() { return arguments; }()); - * // => false - */ - var isArray = nativeIsArray || function (value) { - return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; - }; - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || isObjectLike(value) && objToString.call(value) == boolTag; - } - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - function isDate(value) { - return isObjectLike(value) && objToString.call(value) == dateTag; - } - /** - * Checks if `value` is a DOM element. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return !!value && value.nodeType === 1 && isObjectLike(value) && objToString.call(value).indexOf('Element') > -1; - } - // Fallback for environments without DOM support. - if (!support.dom) { - isElement = function (value) { - return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); - }; - } - /** - * Checks if `value` is empty. A value is considered empty unless it is an - * `arguments` object, array, string, or jQuery-like collection with a length - * greater than `0` or an object with own enumerable properties. - * - * @static - * @memberOf _ - * @category Lang - * @param {Array|Object|string} value The value to inspect. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) || isObjectLike(value) && isFunction(value.splice))) { - return !value.length; - } - return !keys(value).length; - } - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. If `customizer` is provided it is invoked to compare values. - * If `customizer` returns `undefined` comparisons are handled by the method - * instead. The `customizer` is bound to `thisArg` and invoked with three - * arguments: (value, other [, index|key]). - * - * **Note:** This method supports comparing arrays, booleans, `Date` objects, - * numbers, `Object` objects, regexes, and strings. Objects are compared by - * their own, not inherited, enumerable properties. Functions and DOM nodes - * are **not** supported. Provide a customizer function to extend support - * for comparing other values. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'user': 'fred' }; - * var other = { 'user': 'fred' }; - * - * object == other; - * // => false - * - * _.isEqual(object, other); - * // => true - * - * // using a customizer callback - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqual(array, other, function(value, other) { - * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { - * return true; - * } - * }); - * // => true - */ - function isEqual(value, other, customizer, thisArg) { - customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3); - if (!customizer && isStrictComparable(value) && isStrictComparable(other)) { - return value === other; - } - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, customizer) : !!result; - } - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; - } - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on [`Number.isFinite`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.isfinite). - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(10); - * // => true - * - * _.isFinite('10'); - * // => false - * - * _.isFinite(true); - * // => false - * - * _.isFinite(Object(10)); - * // => false - * - * _.isFinite(Infinity); - * // => false - */ - var isFinite = nativeNumIsFinite || function (value) { - return typeof value == 'number' && nativeIsFinite(value); - }; - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - var isFunction = !(baseIsFunction(/x/) || Uint8Array && !baseIsFunction(Uint8Array)) ? baseIsFunction : function (value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in older versions of Chrome and Safari which return 'function' for regexes - // and Safari 8 equivalents which return 'object' for typed array constructors. - return objToString.call(value) == funcTag; - }; - /** - * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. - * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(1); - * // => false - */ - function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return type == 'function' || !!value && type == 'object'; - } - /** - * Performs a deep comparison between `object` and `source` to determine if - * `object` contains equivalent property values. If `customizer` is provided - * it is invoked to compare values. If `customizer` returns `undefined` - * comparisons are handled by the method instead. The `customizer` is bound - * to `thisArg` and invoked with three arguments: (value, other, index|key). - * - * **Note:** This method supports comparing properties of arrays, booleans, - * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions - * and DOM nodes are **not** supported. Provide a customizer function to extend - * support for comparing other values. - * - * @static - * @memberOf _ - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize value comparisons. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.isMatch(object, { 'age': 40 }); - * // => true - * - * _.isMatch(object, { 'age': 36 }); - * // => false - * - * // using a customizer callback - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatch(object, source, function(value, other) { - * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; - * }); - * // => true - */ - function isMatch(object, source, customizer, thisArg) { - var props = keys(source), length = props.length; - if (!length) { - return true; - } - if (object == null) { - return false; - } - customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3); - object = toObject(object); - if (!customizer && length == 1) { - var key = props[0], value = source[key]; - if (isStrictComparable(value)) { - return value === object[key] && (value !== undefined || key in object); - } - } - var values = Array(length), strictCompareFlags = Array(length); - while (length--) { - value = values[length] = source[props[length]]; - strictCompareFlags[length] = isStrictComparable(value); - } - return baseIsMatch(object, props, values, strictCompareFlags, customizer); - } - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4) - * which returns `true` for `undefined` and other non-numeric values. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some host objects in IE. - return isNumber(value) && value != +value; - } - /** - * Checks if `value` is a native function. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (value == null) { - return false; - } - if (objToString.call(value) == funcTag) { - return reIsNative.test(fnToString.call(value)); - } - return isObjectLike(value) && reIsHostCtor.test(value); - } - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified - * as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isNumber(8.4); - * // => true - * - * _.isNumber(NaN); - * // => true - * - * _.isNumber('8.4'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || isObjectLike(value) && objToString.call(value) == numberTag; - } - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * **Note:** This method assumes objects created by the `Object` constructor - * have no inherited enumerable properties. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function (value) { - if (!(value && objToString.call(value) == objectTag)) { - return false; - } - var valueOf = value.valueOf, objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); - return objProto ? value == objProto || getPrototypeOf(value) == objProto : shimIsPlainObject(value); - }; - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - function isRegExp(value) { - return isObjectLike(value) && objToString.call(value) == regexpTag; - } - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || isObjectLike(value) && objToString.call(value) == stringTag; - } - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - function isTypedArray(value) { - return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; - } - /** - * Checks if `value` is `undefined`. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - /** - * Converts `value` to an array. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * (function() { - * return _.toArray(arguments).slice(1); - * }(1, 2, 3)); - * // => [2, 3] - */ - function toArray(value) { - var length = value ? getLength(value) : 0; - if (!isLength(length)) { - return values(value); - } - if (!length) { - return []; - } - return arrayCopy(value); - } - /** - * Converts `value` to a plain object flattening inherited enumerable - * properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return baseCopy(value, keysIn(value)); - } - /** - * Assigns own enumerable properties of source object(s) to the destination - * object. Subsequent sources overwrite property assignments of previous sources. - * If `customizer` is provided it is invoked to produce the assigned values. - * The `customizer` is bound to `thisArg` and invoked with five arguments: - * (objectValue, sourceValue, key, object, source). - * - * **Note:** This method mutates `object` and is based on - * [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign). - * - * @static - * @memberOf _ - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {Object} Returns `object`. - * @example - * - * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); - * // => { 'user': 'fred', 'age': 40 } - * - * // using a customizer callback - * var defaults = _.partialRight(_.assign, function(value, other) { - * return _.isUndefined(value) ? other : value; - * }); - * - * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); - * // => { 'user': 'barney', 'age': 36 } - */ - var assign = createAssigner(function (object, source, customizer) { - return customizer ? assignWith(object, source, customizer) : baseAssign(object, source); - }); - /** - * Creates an object that inherits from the given `prototype` object. If a - * `properties` object is provided its own enumerable properties are assigned - * to the created object. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties, guard) { - var result = baseCreate(prototype); - if (guard && isIterateeCall(prototype, properties, guard)) { - properties = null; - } - return properties ? baseAssign(result, properties) : result; - } - /** - * Assigns own enumerable properties of source object(s) to the destination - * object for all destination properties that resolve to `undefined`. Once a - * property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); - * // => { 'user': 'barney', 'age': 36 } - */ - var defaults = restParam(function (args) { - var object = args[0]; - if (object == null) { - return object; - } - args.push(assignDefaults); - return assign.apply(undefined, args); - }); - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {string|undefined} Returns the key of the matched element, else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(chr) { - * return chr.age < 40; - * }); - * // => 'barney' (iteration order is not guaranteed) - * - * // using the `_.matches` callback shorthand - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // using the `_.matchesProperty` callback shorthand - * _.findKey(users, 'active', false); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.findKey(users, 'active'); - * // => 'barney' - */ - var findKey = createFindKey(baseForOwn); - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * If a property name is provided for `predicate` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `predicate` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to search. - * @param {Function|Object|string} [predicate=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {string|undefined} Returns the key of the matched element, else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(chr) { - * return chr.age < 40; - * }); - * // => returns `pebbles` assuming `_.findKey` returns `barney` - * - * // using the `_.matches` callback shorthand - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // using the `_.matchesProperty` callback shorthand - * _.findLastKey(users, 'active', false); - * // => 'fred' - * - * // using the `_.property` callback shorthand - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - var findLastKey = createFindKey(baseForOwnRight); - /** - * Iterates over own and inherited enumerable properties of an object invoking - * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) - */ - var forIn = createForIn(baseFor); - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' - */ - var forInRight = createForIn(baseForRight); - /** - * Iterates over own enumerable properties of an object invoking `iteratee` - * for each property. The `iteratee` is bound to `thisArg` and invoked with - * three arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'a' and 'b' (iteration order is not guaranteed) - */ - var forOwn = createForOwn(baseForOwn); - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns `object`. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' - */ - var forOwnRight = createForOwn(baseForOwnRight); - /** - * Creates an array of function property names from all enumerable properties, - * own and inherited, of `object`. - * - * @static - * @memberOf _ - * @alias methods - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the new array of property names. - * @example - * - * _.functions(_); - * // => ['after', 'ary', 'assign', ...] - */ - function functions(object) { - return baseFunctions(object, keysIn(object)); - } - /** - * Gets the property value of `path` on `object`. If the resolved value is - * `undefined` the `defaultValue` is used in its place. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, toPath(path), path + ''); - return result === undefined ? defaultValue : result; - } - /** - * Checks if `path` is a direct property. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` is a direct property, else `false`. - * @example - * - * var object = { 'a': { 'b': { 'c': 3 } } }; - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b.c'); - * // => true - * - * _.has(object, ['a', 'b', 'c']); - * // => true - */ - function has(object, path) { - if (object == null) { - return false; - } - var result = hasOwnProperty.call(object, path); - if (!result && !isKey(path)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - path = last(path); - result = object != null && hasOwnProperty.call(object, path); - } - return result; - } - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite property - * assignments of previous values unless `multiValue` is `true`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to invert. - * @param {boolean} [multiValue] Allow multiple values per key. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - * - * // with `multiValue` - * _.invert(object, true); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function invert(object, multiValue, guard) { - if (guard && isIterateeCall(object, multiValue, guard)) { - multiValue = null; - } - var index = -1, props = keys(object), length = props.length, result = {}; - while (++index < length) { - var key = props[index], value = object[key]; - if (multiValue) { - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - } else { - result[value] = key; - } - } - return result; - } - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) - * for more details. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - var keys = !nativeKeys ? shimKeys : function (object) { - var Ctor = object != null && object.constructor; - if (typeof Ctor == 'function' && Ctor.prototype === object || typeof object != 'function' && isArrayLike(object)) { - return shimKeys(object); - } - return isObject(object) ? nativeKeys(object) : []; - }; - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - if (object == null) { - return []; - } - if (!isObject(object)) { - object = Object(object); - } - var length = object.length; - length = length && isLength(length) && (isArray(object) || support.nonEnumArgs && isArguments(object)) && length || 0; - var Ctor = object.constructor, index = -1, isProto = typeof Ctor == 'function' && Ctor.prototype === object, result = Array(length), skipIndexes = length > 0; - while (++index < length) { - result[index] = index + ''; - } - for (var key in object) { - if (!(skipIndexes && isIndex(key, length)) && !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * property of `object` through `iteratee`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the new mapped object. - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - var mapKeys = createObjectMapper(true); - /** - * Creates an object with the same keys as `object` and values generated by - * running each own enumerable property of `object` through `iteratee`. The - * iteratee function is bound to `thisArg` and invoked with three arguments: - * (value, key, object). - * - * If a property name is provided for `iteratee` the created `_.property` - * style callback returns the property value of the given element. - * - * If a value is also provided for `thisArg` the created `_.matchesProperty` - * style callback returns `true` for elements that have a matching property - * value, else `false`. - * - * If an object is provided for `iteratee` the created `_.matches` style - * callback returns `true` for elements that have the properties of the given - * object, else `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function|Object|string} [iteratee=_.identity] The function invoked - * per iteration. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {Object} Returns the new mapped object. - * @example - * - * _.mapValues({ 'a': 1, 'b': 2 }, function(n) { - * return n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * // using the `_.property` callback shorthand - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - var mapValues = createObjectMapper(); - /** - * Recursively merges own enumerable properties of the source object(s), that - * don't resolve to `undefined` into the destination object. Subsequent sources - * overwrite property assignments of previous sources. If `customizer` is - * provided it is invoked to produce the merged values of the destination and - * source properties. If `customizer` returns `undefined` merging is handled - * by the method instead. The `customizer` is bound to `thisArg` and invoked - * with five arguments: (objectValue, sourceValue, key, object, source). - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @param {*} [thisArg] The `this` binding of `customizer`. - * @returns {Object} Returns `object`. - * @example - * - * var users = { - * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] - * }; - * - * var ages = { - * 'data': [{ 'age': 36 }, { 'age': 40 }] - * }; - * - * _.merge(users, ages); - * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } - * - * // using a customizer callback - * var object = { - * 'fruits': ['apple'], - * 'vegetables': ['beet'] - * }; - * - * var other = { - * 'fruits': ['banana'], - * 'vegetables': ['carrot'] - * }; - * - * _.merge(object, other, function(a, b) { - * if (_.isArray(a)) { - * return a.concat(b); - * } - * }); - * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } - */ - var merge = createAssigner(baseMerge); - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable properties of `object` that are not omitted. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to omit, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.omit(object, 'age'); - * // => { 'user': 'fred' } - * - * _.omit(object, _.isNumber); - * // => { 'user': 'fred' } - */ - var omit = restParam(function (object, props) { - if (object == null) { - return {}; - } - if (typeof props[0] != 'function') { - var props = arrayMap(baseFlatten(props), String); - return pickByArray(object, baseDifference(keysIn(object), props)); - } - var predicate = bindCallback(props[0], props[1], 3); - return pickByCallback(object, function (value, key, object) { - return !predicate(value, key, object); - }); - }); - /** - * Creates a two dimensional array of the key-value pairs for `object`, - * e.g. `[[key1, value1], [key2, value2]]`. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. - * @example - * - * _.pairs({ 'barney': 36, 'fred': 40 }); - * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) - */ - function pairs(object) { - var index = -1, props = keys(object), length = props.length, result = Array(length); - while (++index < length) { - var key = props[index]; - result[index] = [ - key, - object[key] - ]; - } - return result; - } - /** - * Creates an object composed of the picked `object` properties. Property - * names may be specified as individual arguments or as arrays of property - * names. If `predicate` is provided it is invoked for each property of `object` - * picking the properties `predicate` returns truthy for. The predicate is - * bound to `thisArg` and invoked with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {Function|...(string|string[])} [predicate] The function invoked per - * iteration or property names to pick, specified as individual property - * names or arrays of property names. - * @param {*} [thisArg] The `this` binding of `predicate`. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'user': 'fred', 'age': 40 }; - * - * _.pick(object, 'user'); - * // => { 'user': 'fred' } - * - * _.pick(object, _.isString); - * // => { 'user': 'fred' } - */ - var pick = restParam(function (object, props) { - if (object == null) { - return {}; - } - return typeof props[0] == 'function' ? pickByCallback(object, bindCallback(props[0], props[1], 3)) : pickByArray(object, baseFlatten(props)); - }); - /** - * This method is like `_.get` except that if the resolved value is a function - * it is invoked with the `this` binding of its parent object and its result - * is returned. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a.b.c', 'default'); - * // => 'default' - * - * _.result(object, 'a.b.c', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - var result = object == null ? undefined : object[path]; - if (result === undefined) { - if (object != null && !isKey(path, object)) { - path = toPath(path); - object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - result = object == null ? undefined : object[last(path)]; - } - result = result === undefined ? defaultValue : result; - } - return isFunction(result) ? result.call(object) : result; - } - /** - * Sets the property value of `path` on `object`. If a portion of `path` - * does not exist it is created. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to augment. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, 'x[0].y.z', 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - if (object == null) { - return object; - } - var pathKey = path + ''; - path = object[pathKey] != null || isKey(path, object) ? [pathKey] : toPath(path); - var index = -1, length = path.length, endIndex = length - 1, nested = object; - while (nested != null && ++index < length) { - var key = path[index]; - if (isObject(nested)) { - if (index == endIndex) { - nested[key] = value; - } else if (nested[key] == null) { - nested[key] = isIndex(path[index + 1]) ? [] : {}; - } - } - nested = nested[key]; - } - return object; - } - /** - * An alternative to `_.reduce`; this method transforms `object` to a new - * `accumulator` object which is the result of running each of its own enumerable - * properties through `iteratee`, with each invocation potentially mutating - * the `accumulator` object. The `iteratee` is bound to `thisArg` and invoked - * with four arguments: (accumulator, value, key, object). Iteratee functions - * may exit iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @category Object - * @param {Array|Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The custom accumulator value. - * @param {*} [thisArg] The `this` binding of `iteratee`. - * @returns {*} Returns the accumulated value. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2 }, function(result, n, key) { - * result[key] = n * 3; - * }); - * // => { 'a': 3, 'b': 6 } - */ - function transform(object, iteratee, accumulator, thisArg) { - var isArr = isArray(object) || isTypedArray(object); - iteratee = getCallback(iteratee, thisArg, 4); - if (accumulator == null) { - if (isArr || isObject(object)) { - var Ctor = object.constructor; - if (isArr) { - accumulator = isArray(object) ? new Ctor() : []; - } else { - accumulator = baseCreate(isFunction(Ctor) && Ctor.prototype); - } - } else { - accumulator = {}; - } - } - (isArr ? arrayEach : baseForOwn)(object, function (value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } - /** - * Creates an array of the own enumerable property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return baseValues(object, keys(object)); - } - /** - * Creates an array of the own and inherited enumerable property values - * of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return baseValues(object, keysIn(object)); - } - /** - * Checks if `n` is between `start` and up to but not including, `end`. If - * `end` is not specified it is set to `start` with `start` then set to `0`. - * - * @static - * @memberOf _ - * @category Number - * @param {number} n The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `n` is in the range, else `false`. - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - */ - function inRange(value, start, end) { - start = +start || 0; - if (typeof end === 'undefined') { - end = start; - start = 0; - } else { - end = +end || 0; - } - return value >= nativeMin(start, end) && value < nativeMax(start, end); - } - /** - * Produces a random number between `min` and `max` (inclusive). If only one - * argument is provided a number between `0` and the given number is returned. - * If `floating` is `true`, or either `min` or `max` are floats, a floating-point - * number is returned instead of an integer. - * - * @static - * @memberOf _ - * @category Number - * @param {number} [min=0] The minimum possible value. - * @param {number} [max=1] The maximum possible value. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(min, max, floating) { - if (floating && isIterateeCall(min, max, floating)) { - max = floating = null; - } - var noMin = min == null, noMax = max == null; - if (floating == null) { - if (noMax && typeof min == 'boolean') { - floating = min; - min = 1; - } else if (typeof max == 'boolean') { - floating = max; - noMax = true; - } - } - if (noMin && noMax) { - max = 1; - noMax = false; - } - min = +min || 0; - if (noMax) { - max = min; - min = 0; - } else { - max = +max || 0; - } - if (floating || min % 1 || max % 1) { - var rand = nativeRandom(); - return nativeMin(min + rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1))), max); - } - return baseRandom(min, max); - } - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar'); - * // => 'fooBar' - * - * _.camelCase('__foo_bar__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function (result, word, index) { - word = word.toLowerCase(); - return result + (index ? word.charAt(0).toUpperCase() + word.slice(1) : word); - }); - /** - * Capitalizes the first character of `string`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('fred'); - * // => 'Fred' - */ - function capitalize(string) { - string = baseToString(string); - return string && string.charAt(0).toUpperCase() + string.slice(1); - } - /** - * Deburrs `string` by converting [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * to basic latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('déjà vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = baseToString(string); - return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, ''); - } - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to search. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search from. - * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = baseToString(string); - target = target + ''; - var length = string.length; - position = position === undefined ? length : nativeMin(position < 0 ? 0 : +position || 0, length); - position -= target.length; - return position >= 0 && string.indexOf(target, position) == position; - } - /** - * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to - * their corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional characters - * use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't require escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. - * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * Backticks are escaped because in Internet Explorer < 9, they can break out - * of attribute values or HTML comments. See [#59](https://html5sec.org/#59), - * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and - * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/) - * for more details. - * - * When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping) - * to reduce XSS vectors. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - // Reset `lastIndex` because in IE < 9 `String#replace` does not. - string = baseToString(string); - return string && reHasUnescapedHtml.test(string) ? string.replace(reUnescapedHtml, escapeHtmlChar) : string; - } - /** - * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", - * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' - */ - function escapeRegExp(string) { - string = baseToString(string); - return string && reHasRegExpChars.test(string) ? string.replace(reRegExpChars, '\\$&') : string; - } - /** - * Converts `string` to [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__foo_bar__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function (result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); - }); - /** - * Pads `string` on the left and right sides if it is shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = baseToString(string); - length = +length; - var strLength = string.length; - if (strLength >= length || !nativeIsFinite(length)) { - return string; - } - var mid = (length - strLength) / 2, leftLength = floor(mid), rightLength = ceil(mid); - chars = createPadding('', rightLength, chars); - return chars.slice(0, leftLength) + string + chars; - } - /** - * Pads `string` on the left side if it is shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padLeft('abc', 6); - * // => ' abc' - * - * _.padLeft('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padLeft('abc', 3); - * // => 'abc' - */ - var padLeft = createPadDir(); - /** - * Pads `string` on the right side if it is shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padRight('abc', 6); - * // => 'abc ' - * - * _.padRight('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padRight('abc', 3); - * // => 'abc' - */ - var padRight = createPadDir(true); - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, - * in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the [ES5 implementation](https://es5.github.io/#E) - * of `parseInt`. - * - * @static - * @memberOf _ - * @category String - * @param {string} string The string to convert. - * @param {number} [radix] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - if (guard && isIterateeCall(string, radix, guard)) { - radix = 0; - } - return nativeParseInt(string, radix); - } - // Fallback for environments with pre-ES5 implementations. - if (nativeParseInt(whitespace + '08') != 8) { - parseInt = function (string, radix, guard) { - // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. - // Chrome fails to trim leading whitespace characters. - // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. - if (guard ? isIterateeCall(string, radix, guard) : radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - string = trim(string); - return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10)); - }; - } - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=0] The number of times to repeat the string. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n) { - var result = ''; - string = baseToString(string); - n = +n; - if (n < 1 || !string || !nativeIsFinite(n)) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = floor(n / 2); - string += string; - } while (n); - return result; - } - /** - * Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--foo-bar'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function (result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); - /** - * Converts `string` to [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__foo_bar__'); - * // => 'Foo Bar' - */ - var startCase = createCompounder(function (result, word, index) { - return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1)); - }); - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The string to search. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = baseToString(string); - position = position == null ? 0 : nativeMin(position < 0 ? 0 : +position || 0, string.length); - return string.lastIndexOf(target, position) == position; - } - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is provided it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options] The options object. - * @param {RegExp} [options.escape] The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate] The "evaluate" delimiter. - * @param {Object} [options.imports] An object to import into the template as free variables. - * @param {RegExp} [options.interpolate] The "interpolate" delimiter. - * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. - * @param {string} [options.variable] The data object variable name. - * @param- {Object} [otherOptions] Enables the legacy `options` param signature. - * @returns {Function} Returns the compiled template function. - * @example - * - * // using the "interpolate" delimiter to create a compiled template - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // using the HTML "escape" delimiter to escape data property values - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': ' -
- 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(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). - toBe('

an html\nclick here\nsnippet

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

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

"); - }); - - it('should escape snippet without any filter', function() { - expect(element(by.css('#bind-default div')).getInnerHtml()). - toBe("<p style=\"color:blue\">an html\n" + - "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + - "snippet</p>"); - }); - - it('should update', function() { - element(by.model('snippet')).clear(); - element(by.model('snippet')).sendKeys('new text'); - expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). - toBe('new text'); - expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( - 'new text'); - expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( - "new <b onclick=\"alert(1)\">text</b>"); - }); -
- - */ - - -/** - * @ngdoc provider - * @name $sanitizeProvider - * - * @description - * Creates and configures {@link $sanitize} instance. - */ -function $SanitizeProvider() { - var svgEnabled = false; - - this.$get = ['$$sanitizeUri', function($$sanitizeUri) { - if (svgEnabled) { - angular.extend(validElements, svgElements); - } - return function(html) { - var buf = []; - htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { - return !/^unsafe:/.test($$sanitizeUri(uri, isImage)); - })); - return buf.join(''); - }; - }]; - - - /** - * @ngdoc method - * @name $sanitizeProvider#enableSvg - * @kind function - * - * @description - * Enables a subset of svg to be supported by the sanitizer. - * - *
- *

By enabling this setting without taking other precautions, you might expose your - * application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned - * outside of the containing element and be rendered over other elements on the page (e.g. a login - * link). Such behavior can then result in phishing incidents.

- * - *

To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg - * tags within the sanitized content:

- * - *
- * - *

-   *   .rootOfTheIncludedContent svg {
-   *     overflow: hidden !important;
-   *   }
-   *   
- *
- * - * @param {boolean=} regexp New regexp to whitelist urls with. - * @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called - * without an argument or self for chaining otherwise. - */ - this.enableSvg = function(enableSvg) { - if (angular.isDefined(enableSvg)) { - svgEnabled = enableSvg; - return this; - } else { - return svgEnabled; - } - }; -} - -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 SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/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 = toMap("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 = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), - optionalEndTagInlineElements = toMap("rp,rt"), - optionalEndTagElements = angular.extend({}, - optionalEndTagInlineElements, - optionalEndTagBlockElements); - -// Safe Block Elements - HTML5 -var blockElements = angular.extend({}, optionalEndTagBlockElements, toMap("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,section,table,ul")); - -// Inline Elements - HTML5 -var inlineElements = angular.extend({}, optionalEndTagInlineElements, toMap("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")); - -// SVG Elements -// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements -// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. -// They can potentially allow for arbitrary javascript to be executed. See #11290 -var svgElements = toMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," + - "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," + - "radialGradient,rect,stop,svg,switch,text,title,tspan"); - -// Blocked Elements (will be stripped) -var blockedElements = toMap("script,style"); - -var validElements = angular.extend({}, - voidElements, - blockElements, - inlineElements, - optionalEndTagElements); - -//Attributes that have href and hence need to be sanitized -var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href"); - -var htmlAttrs = toMap('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,size,span,start,summary,tabindex,target,title,type,' + - 'valign,value,vspace,width'); - -// SVG attributes (without "id" and "name" attributes) -// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes -var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + - 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + - 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + - 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + - 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' + - 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' + - 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' + - 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' + - 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' + - 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' + - 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' + - 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' + - 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' + - 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' + - 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true); - -var validAttrs = angular.extend({}, - uriAttrs, - svgAttrs, - htmlAttrs); - -function toMap(str, lowercaseKeys) { - var obj = {}, items = str.split(','), i; - for (i = 0; i < items.length; i++) { - obj[lowercaseKeys ? angular.lowercase(items[i]) : items[i]] = true; - } - return obj; -} - -var inertBodyElement; -(function(window) { - var doc; - if (window.document && window.document.implementation) { - doc = window.document.implementation.createHTMLDocument("inert"); - } else { - throw $sanitizeMinErr('noinert', "Can't create an inert html document"); - } - var docElement = doc.documentElement || doc.getDocumentElement(); - var bodyElements = docElement.getElementsByTagName('body'); - - // usually there should be only one body element in the document, but IE doesn't have any, so we need to create one - if (bodyElements.length === 1) { - inertBodyElement = bodyElements[0]; - } else { - var html = doc.createElement('html'); - inertBodyElement = doc.createElement('body'); - html.appendChild(inertBodyElement); - doc.appendChild(html); - } -})(window); - -/** - * @example - * htmlParser(htmlString, { - * start: function(tag, attrs) {}, - * end: function(tag) {}, - * chars: function(text) {}, - * comment: function(text) {} - * }); - * - * @param {string} html string - * @param {object} handler - */ -function htmlParser(html, handler) { - if (html === null || html === undefined) { - html = ''; - } else if (typeof html !== 'string') { - html = '' + html; - } - inertBodyElement.innerHTML = html; - - //mXSS protection - var mXSSAttempts = 5; - do { - if (mXSSAttempts === 0) { - throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable"); - } - mXSSAttempts--; - - // strip custom-namespaced attributes on IE<=11 - if (document.documentMode <= 11) { - stripCustomNsAttrs(inertBodyElement); - } - html = inertBodyElement.innerHTML; //trigger mXSS - inertBodyElement.innerHTML = html; - } while (html !== inertBodyElement.innerHTML); - - var node = inertBodyElement.firstChild; - while (node) { - switch (node.nodeType) { - case 1: // ELEMENT_NODE - handler.start(node.nodeName.toLowerCase(), attrToMap(node.attributes)); - break; - case 3: // TEXT NODE - handler.chars(node.textContent); - break; - } - - var nextNode; - if (!(nextNode = node.firstChild)) { - if (node.nodeType == 1) { - handler.end(node.nodeName.toLowerCase()); - } - nextNode = node.nextSibling; - if (!nextNode) { - while (nextNode == null) { - node = node.parentNode; - if (node === inertBodyElement) break; - nextNode = node.nextSibling; - if (node.nodeType == 1) { - handler.end(node.nodeName.toLowerCase()); - } - } - } - } - node = nextNode; - } - - while (node = inertBodyElement.firstChild) { - inertBodyElement.removeChild(node); - } -} - -function attrToMap(attrs) { - var map = {}; - for (var i = 0, ii = attrs.length; i < ii; i++) { - var attr = attrs[i]; - map[attr.name] = attr.value; - } - return map; -} - - -/** - * Escapes all potentially dangerous characters, so that the - * resulting string can be safely inserted into attribute or - * element text. - * @param value - * @returns {string} escaped text - */ -function encodeEntities(value) { - return value. - replace(/&/g, '&'). - replace(SURROGATE_PAIR_REGEXP, function(value) { - var hi = value.charCodeAt(0); - var low = value.charCodeAt(1); - return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'; - }). - replace(NON_ALPHANUMERIC_REGEXP, function(value) { - return '&#' + value.charCodeAt(0) + ';'; - }). - replace(//g, '>'); -} - -/** - * create an HTML/XML writer which writes to buffer - * @param {Array} buf use buf.join('') to get out sanitized html string - * @returns {object} in the form of { - * start: function(tag, attrs) {}, - * end: function(tag) {}, - * chars: function(text) {}, - * comment: function(text) {} - * } - */ -function htmlSanitizeWriter(buf, uriValidator) { - var ignoreCurrentElement = false; - var out = angular.bind(buf, buf.push); - return { - start: function(tag, attrs) { - tag = angular.lowercase(tag); - if (!ignoreCurrentElement && blockedElements[tag]) { - ignoreCurrentElement = tag; - } - if (!ignoreCurrentElement && 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('>'); - } - }, - end: function(tag) { - tag = angular.lowercase(tag); - if (!ignoreCurrentElement && validElements[tag] === true && voidElements[tag] !== true) { - out(''); - } - if (tag == ignoreCurrentElement) { - ignoreCurrentElement = false; - } - }, - chars: function(chars) { - if (!ignoreCurrentElement) { - out(encodeEntities(chars)); - } - } - }; -} - - -/** - * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare - * ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want - * to allow any of these custom attributes. This method strips them all. - * - * @param node Root element to process - */ -function stripCustomNsAttrs(node) { - if (node.nodeType === Node.ELEMENT_NODE) { - var attrs = node.attributes; - for (var i = 0, l = attrs.length; i < l; i++) { - var attrNode = attrs[i]; - var attrName = attrNode.name.toLowerCase(); - if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) { - node.removeAttributeNode(attrNode); - i--; - l--; - } - } - } - - var nextNode = node.firstChild; - if (nextNode) { - stripCustomNsAttrs(nextNode); - } - - nextNode = node.nextSibling; - if (nextNode) { - stripCustomNsAttrs(nextNode); - } -} - - - -// define ngSanitize module and register $sanitize service -angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); - -/* global sanitizeText: false */ - -/** - * @ngdoc filter - * @name linky - * @kind 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. - * @param {object|function(url)} [attributes] Add custom attributes to the link element. - * - * Can be one of: - * - * - `object`: A map of attributes - * - `function`: Takes the url as a parameter and returns a map of attributes - * - * If the map of attributes contains a value for `target`, it overrides the value of - * the target parameter. - * - * - * @returns {string} Html-linkified and {@link $sanitize sanitized} text. - * - * @usage - - * - * @example - - -
- Snippet: - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilterSourceRendered
linky filter -
<div ng-bind-html="snippet | linky">
</div>
-
-
-
linky target -
<div ng-bind-html="snippetWithSingleURL | linky:'_blank'">
</div>
-
-
-
linky custom attributes -
<div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}">
</div>
-
-
-
no filter
<div ng-bind="snippet">
</div>
- - - angular.module('linkyExample', ['ngSanitize']) - .controller('ExampleController', ['$scope', function($scope) { - $scope.snippet = - '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/.'; - $scope.snippetWithSingleURL = 'http://angularjs.org/'; - }]); - - - it('should linkify the snippet with urls', function() { - expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). - toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + - 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); - expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); - }); - - it('should not linkify snippet without the linky filter', function() { - expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). - toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + - 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); - expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); - }); - - it('should update', function() { - element(by.model('snippet')).clear(); - element(by.model('snippet')).sendKeys('new http://link.'); - expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). - toBe('new http://link.'); - expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); - expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) - .toBe('new http://link.'); - }); - - it('should work with the target property', function() { - expect(element(by.id('linky-target')). - element(by.binding("snippetWithSingleURL | linky:'_blank'")).getText()). - toBe('http://angularjs.org/'); - expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); - }); - - it('should optionally add custom attributes', function() { - expect(element(by.id('linky-custom-attributes')). - element(by.binding("snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}")).getText()). - toBe('http://angularjs.org/'); - expect(element(by.css('#linky-custom-attributes a')).getAttribute('rel')).toEqual('nofollow'); - }); - - - */ -angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { - var LINKY_URL_REGEXP = - /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i, - MAILTO_REGEXP = /^mailto:/i; - - var linkyMinErr = angular.$$minErr('linky'); - var isString = angular.isString; - - return function(text, target, attributes) { - if (text == null || text === '') return text; - if (!isString(text)) throw linkyMinErr('notstring', 'Expected string but received: {0}', 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/www/mailto then assume mailto - if (!match[2] && !match[4]) { - url = (match[3] ? 'http://' : '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) { - var key; - html.push(''); - addText(text); - html.push(''); - } - }; -}]); - - -})(window, window.angular); - -(function(window, document) { - -// Create all modules and define dependencies to make sure they exist -// and are loaded in the correct order to satisfy dependency injection -// before all nested files are concatenated by Grunt - -// Config -angular.module('ngCsv.config', []). - value('ngCsv.config', { - debug: true - }). - config(['$compileProvider', function($compileProvider){ - if (angular.isDefined($compileProvider.urlSanitizationWhitelist)) { - $compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|data):/); - } else { - $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|data):/); - } - }]); - -// Modules -angular.module('ngCsv.directives', ['ngCsv.services']); -angular.module('ngCsv.services', []); -angular.module('ngCsv', - [ - 'ngCsv.config', - 'ngCsv.services', - 'ngCsv.directives', - 'ngSanitize' - ]); - -// Common.js package manager support (e.g. ComponentJS, WebPack) -if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports) { - module.exports = 'ngCsv'; -} -/** - * Created by asafdav on 15/05/14. - */ -angular.module('ngCsv.services'). - service('CSV', ['$q', function ($q) { - - var EOL = '\r\n'; - var BOM = "\ufeff"; - - var specialChars = { - '\\t': '\t', - '\\b': '\b', - '\\v': '\v', - '\\f': '\f', - '\\r': '\r' - }; - - /** - * Stringify one field - * @param data - * @param options - * @returns {*} - */ - this.stringifyField = function (data, options) { - if (options.decimalSep === 'locale' && this.isFloat(data)) { - return data.toLocaleString(); - } - - if (options.decimalSep !== '.' && this.isFloat(data)) { - return data.toString().replace('.', options.decimalSep); - } - - if (typeof data === 'string') { - data = data.replace(/"/g, '""'); // Escape double qoutes - - if (options.quoteStrings || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) { - data = options.txtDelim + data + options.txtDelim; - } - - return data; - } - - if (typeof data === 'boolean') { - return data ? 'TRUE' : 'FALSE'; - } - - return data; - }; - - /** - * Helper function to check if input is float - * @param input - * @returns {boolean} - */ - this.isFloat = function (input) { - return +input === input && (!isFinite(input) || Boolean(input % 1)); - }; - - /** - * Creates a csv from a data array - * @param data - * @param options - * * header - Provide the first row (optional) - * * fieldSep - Field separator, default: ',', - * * addByteOrderMarker - Add Byte order mark, default(false) - * @param callback - */ - this.stringify = function (data, options) { - var def = $q.defer(); - - var that = this; - var csv = ""; - var csvContent = ""; - - var dataPromise = $q.when(data).then(function (responseData) { - //responseData = angular.copy(responseData);//moved to row creation - // Check if there's a provided header array - if (angular.isDefined(options.header) && options.header) { - var encodingArray, headerString; - - encodingArray = []; - angular.forEach(options.header, function (title, key) { - this.push(that.stringifyField(title, options)); - }, encodingArray); - - headerString = encodingArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += headerString + EOL; - } - - var arrData = []; - - if (angular.isArray(responseData)) { - arrData = responseData; - } - else if (angular.isFunction(responseData)) { - arrData = responseData(); - } - - // Check if using keys as labels - if (angular.isDefined(options.label) && options.label && typeof options.label === 'boolean') { - var labelArray, labelString; - - labelArray = []; - angular.forEach(arrData[0], function(value, label) { - this.push(that.stringifyField(label, options)); - }, labelArray); - labelString = labelArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += labelString + EOL; - } - - angular.forEach(arrData, function (oldRow, index) { - var row = angular.copy(arrData[index]); - var dataString, infoArray; - - infoArray = []; - - var iterator = !!options.columnOrder ? options.columnOrder : row; - angular.forEach(iterator, function (field, key) { - var val = !!options.columnOrder ? row[field] : field; - this.push(that.stringifyField(val, options)); - }, infoArray); - - dataString = infoArray.join(options.fieldSep ? options.fieldSep : ","); - csvContent += index < arrData.length ? dataString + EOL : dataString; - }); - - // Add BOM if needed - if (options.addByteOrderMarker) { - csv += BOM; - } - - // Append the content and resolve. - csv += csvContent; - def.resolve(csv); - }); - - if (typeof dataPromise['catch'] === 'function') { - dataPromise['catch'](function (err) { - def.reject(err); - }); - } - - return def.promise; - }; - - /** - * Helper function to check if input is really a special character - * @param input - * @returns {boolean} - */ - this.isSpecialChar = function(input){ - return specialChars[input] !== undefined; - }; - - /** - * Helper function to get what the special character was supposed to be - * since Angular escapes the first backslash - * @param input - * @returns {special character string} - */ - this.getSpecialChar = function (input) { - return specialChars[input]; - }; - - - }]); -/** - * ng-csv module - * Export Javascript's arrays to csv files from the browser - * - * Author: asafdav - https://github.com/asafdav - */ -angular.module('ngCsv.directives'). - directive('ngCsv', ['$parse', '$q', 'CSV', '$document', '$timeout', function ($parse, $q, CSV, $document, $timeout) { - return { - restrict: 'AC', - scope: { - data: '&ngCsv', - filename: '@filename', - header: '&csvHeader', - columnOrder: '&csvColumnOrder', - txtDelim: '@textDelimiter', - decimalSep: '@decimalSeparator', - quoteStrings: '@quoteStrings', - fieldSep: '@fieldSeparator', - lazyLoad: '@lazyLoad', - addByteOrderMarker: "@addBom", - ngClick: '&', - charset: '@charset', - label: '&csvLabel' - }, - controller: [ - '$scope', - '$element', - '$attrs', - '$transclude', - function ($scope, $element, $attrs, $transclude) { - $scope.csv = ''; - - if (!angular.isDefined($scope.lazyLoad) || $scope.lazyLoad != "true") { - if (angular.isArray($scope.data)) { - $scope.$watch("data", function (newValue) { - $scope.buildCSV(); - }, true); - } - } - - $scope.getFilename = function () { - return $scope.filename || 'download.csv'; - }; - - function getBuildCsvOptions() { - var options = { - txtDelim: $scope.txtDelim ? $scope.txtDelim : '"', - decimalSep: $scope.decimalSep ? $scope.decimalSep : '.', - quoteStrings: $scope.quoteStrings, - addByteOrderMarker: $scope.addByteOrderMarker - }; - if (angular.isDefined($attrs.csvHeader)) options.header = $scope.$eval($scope.header); - if (angular.isDefined($attrs.csvColumnOrder)) options.columnOrder = $scope.$eval($scope.columnOrder); - if (angular.isDefined($attrs.csvLabel)) options.label = $scope.$eval($scope.label); - - options.fieldSep = $scope.fieldSep ? $scope.fieldSep : ","; - - // Replaces any badly formatted special character string with correct special character - options.fieldSep = CSV.isSpecialChar(options.fieldSep) ? CSV.getSpecialChar(options.fieldSep) : options.fieldSep; - - return options; - } - - /** - * Creates the CSV and updates the scope - * @returns {*} - */ - $scope.buildCSV = function () { - var deferred = $q.defer(); - - $element.addClass($attrs.ngCsvLoadingClass || 'ng-csv-loading'); - - CSV.stringify($scope.data(), getBuildCsvOptions()).then(function (csv) { - $scope.csv = csv; - $element.removeClass($attrs.ngCsvLoadingClass || 'ng-csv-loading'); - deferred.resolve(csv); - }); - $scope.$apply(); // Old angular support - - return deferred.promise; - }; - } - ], - link: function (scope, element, attrs) { - function doClick() { - var charset = scope.charset || "utf-8"; - var blob = new Blob([scope.csv], { - type: "text/csv;charset="+ charset + ";" - }); - - if (window.navigator.msSaveOrOpenBlob) { - navigator.msSaveBlob(blob, scope.getFilename()); - } else { - - var downloadContainer = angular.element('
'); - var downloadLink = angular.element(downloadContainer.children()[0]); - downloadLink.attr('href', window.URL.createObjectURL(blob)); - downloadLink.attr('download', scope.getFilename()); - downloadLink.attr('target', '_blank'); - - $document.find('body').append(downloadContainer); - $timeout(function () { - downloadLink[0].click(); - downloadLink.remove(); - }, null); - } - } - - element.bind('click', function (e) { - scope.buildCSV().then(function (csv) { - doClick(); - }); - scope.$apply(); - }); - } - }; - }]); -})(window, document); -/** - * @license AngularJS v1.4.10 - * (c) 2010-2015 Google, Inc. http://angularjs.org - * License: MIT - */ -(function(window, angular, undefined) { - -'use strict'; - -/** - * @ngdoc object - * @name angular.mock - * @description - * - * Namespace from 'angular-mocks.js' which contains testing related code. - */ -angular.mock = {}; - -/** - * ! This is a private undocumented service ! - * - * @name $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.$$state !== self.$$lastState) { - self.$$lastUrl = self.$$url; - self.$$lastState = self.$$state; - listener(self.$$url, self.$$state); - } - } - ); - - return listener; - }; - - self.$$applicationDestroyed = angular.noop; - self.$$checkUrlChange = angular.noop; - - 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 $browser#defer.now - * - * @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 (angular.isDefined(fnIndex)) { - self.deferredFns.splice(fnIndex, 1); - return true; - } - - return false; - }; - - - /** - * @name $browser#defer.flush - * - * @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 $browser#poll - * - * @description - * run all fns in pollFns - */ - poll: function poll() { - angular.forEach(this.pollFns, function(pollFn) { - pollFn(); - }); - }, - - url: function(url, replace, state) { - if (angular.isUndefined(state)) { - state = null; - } - if (url) { - this.$$url = url; - // Native pushState serializes & copies the object; simulate it. - this.$$state = angular.copy(state); - return this; - } - - return this.$$url; - }, - - state: function() { - return this.$$state; - }, - - notifyWhenNoOutstandingRequests: function(fn) { - fn(); - } -}; - - -/** - * @ngdoc provider - * @name $exceptionHandlerProvider - * - * @description - * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors - * passed to the `$exceptionHandler`. - */ - -/** - * @ngdoc service - * @name $exceptionHandler - * - * @description - * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed - * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration - * information. - * - * - * ```js - * 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 $exceptionHandlerProvider#mode - * - * @description - * Sets the logging mode. - * - * @param {string} mode Mode of operation, defaults to `rethrow`. - * - * - `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()} - * - `rethrow`: If any errors are passed to 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. - * For any implementations that expect exceptions to be thrown, the `rethrow` mode - * will also maintain a log of thrown errors. - */ - this.mode = function(mode) { - - switch (mode) { - case 'log': - case 'rethrow': - var errors = []; - handler = function(e) { - if (arguments.length == 1) { - errors.push(e); - } else { - errors.push([].slice.call(arguments, 0)); - } - if (mode === "rethrow") { - throw e; - } - }; - 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 $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 $log#reset - * - * @description - * Reset all of the logging arrays to empty. - */ - $log.reset = function() { - /** - * @ngdoc property - * @name $log#log.logs - * - * @description - * Array of messages logged using {@link ng.$log#log `log()`}. - * - * @example - * ```js - * $log.log('Some Log'); - * var first = $log.log.logs.unshift(); - * ``` - */ - $log.log.logs = []; - /** - * @ngdoc property - * @name $log#info.logs - * - * @description - * Array of messages logged using {@link ng.$log#info `info()`}. - * - * @example - * ```js - * $log.info('Some Info'); - * var first = $log.info.logs.unshift(); - * ``` - */ - $log.info.logs = []; - /** - * @ngdoc property - * @name $log#warn.logs - * - * @description - * Array of messages logged using {@link ng.$log#warn `warn()`}. - * - * @example - * ```js - * $log.warn('Some Warning'); - * var first = $log.warn.logs.unshift(); - * ``` - */ - $log.warn.logs = []; - /** - * @ngdoc property - * @name $log#error.logs - * - * @description - * Array of messages logged using {@link ng.$log#error `error()`}. - * - * @example - * ```js - * $log.error('Some Error'); - * var first = $log.error.logs.unshift(); - * ``` - */ - $log.error.logs = []; - /** - * @ngdoc property - * @name $log#debug.logs - * - * @description - * Array of messages logged using {@link ng.$log#debug `debug()`}. - * - * @example - * ```js - * $log.debug('Some Error'); - * var first = $log.debug.logs.unshift(); - * ``` - */ - $log.debug.logs = []; - }; - - /** - * @ngdoc method - * @name $log#assertEmpty - * - * @description - * Assert that all of the logging methods have no logged messages. If any messages are 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 $interval - * - * @description - * Mock implementation of the $interval service. - * - * Use {@link ngMock.$interval#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#$apply $apply} block. - * @param {...*=} Pass additional parameters to the executed function. - * @returns {promise} A promise which will be notified on each iteration. - */ -angular.mock.$IntervalProvider = function() { - this.$get = ['$browser', '$rootScope', '$q', '$$q', - function($browser, $rootScope, $q, $$q) { - var repeatFns = [], - nextRepeatId = 0, - now = 0; - - var $interval = function(fn, delay, count, invokeApply) { - var hasParams = arguments.length > 4, - args = hasParams ? Array.prototype.slice.call(arguments, 4) : [], - iteration = 0, - skipApply = (angular.isDefined(invokeApply) && !invokeApply), - deferred = (skipApply ? $$q : $q).defer(), - promise = deferred.promise; - - count = (angular.isDefined(count)) ? count : 0; - promise.then(null, null, (!hasParams) ? fn : function() { - fn.apply(null, args); - }); - - 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 (angular.isDefined(fnIndex)) { - repeatFns.splice(fnIndex, 1); - } - } - - if (skipApply) { - $browser.defer.flush(); - } else { - $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; - }; - /** - * @ngdoc method - * @name $interval#cancel - * - * @description - * Cancels a task associated with the `promise`. - * - * @param {promise} promise A promise from calling the `$interval` function. - * @returns {boolean} Returns `true` if the task was successfully cancelled. - */ - $interval.cancel = function(promise) { - if (!promise) return false; - var fnIndex; - - angular.forEach(repeatFns, function(fn, index) { - if (fn.id === promise.$$intervalId) fnIndex = index; - }); - - if (angular.isDefined(fnIndex)) { - repeatFns[fnIndex].deferred.reject('canceled'); - repeatFns.splice(fnIndex, 1); - return true; - } - - return false; - }; - - /** - * @ngdoc method - * @name $interval#flush - * @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 = toInt(match[9] + match[10]); - tzMin = toInt(match[9] + match[11]); - } - date.setUTCFullYear(toInt(match[1]), toInt(match[2]) - 1, toInt(match[3])); - date.setUTCHours(toInt(match[4] || 0) - tzHour, - toInt(match[5] || 0) - tzMin, - toInt(match[6] || 0), - toInt(match[7] || 0)); - return date; - } - return string; -} - -function toInt(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 type - * @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". - * - * ```js - * 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 */ - - -/** - * @ngdoc service - * @name $animate - * - * @description - * Mock implementation of the {@link ng.$animate `$animate`} service. Exposes two additional methods - * for testing animations. - */ -angular.mock.animate = angular.module('ngAnimateMock', ['ng']) - - .config(['$provide', function($provide) { - - $provide.factory('$$forceReflow', function() { - function reflowFn() { - reflowFn.totalReflows++; - } - reflowFn.totalReflows = 0; - return reflowFn; - }); - - $provide.factory('$$animateAsyncRun', function() { - var queue = []; - var queueFn = function() { - return function(fn) { - queue.push(fn); - }; - }; - queueFn.flush = function() { - if (queue.length === 0) return false; - - for (var i = 0; i < queue.length; i++) { - queue[i](); - } - queue = []; - - return true; - }; - return queueFn; - }); - - $provide.decorator('$$animateJs', ['$delegate', function($delegate) { - var runners = []; - - var animateJsConstructor = function() { - var animator = $delegate.apply($delegate, arguments); - // If no javascript animation is found, animator is undefined - if (animator) { - runners.push(animator); - } - return animator; - }; - - animateJsConstructor.$closeAndFlush = function() { - runners.forEach(function(runner) { - runner.end(); - }); - runners = []; - }; - - return animateJsConstructor; - }]); - - $provide.decorator('$animateCss', ['$delegate', function($delegate) { - var runners = []; - - var animateCssConstructor = function(element, options) { - var animator = $delegate(element, options); - runners.push(animator); - return animator; - }; - - animateCssConstructor.$closeAndFlush = function() { - runners.forEach(function(runner) { - runner.end(); - }); - runners = []; - }; - - return animateCssConstructor; - }]); - - $provide.decorator('$animate', ['$delegate', '$timeout', '$browser', '$$rAF', '$animateCss', '$$animateJs', - '$$forceReflow', '$$animateAsyncRun', '$rootScope', - function($delegate, $timeout, $browser, $$rAF, $animateCss, $$animateJs, - $$forceReflow, $$animateAsyncRun, $rootScope) { - var animate = { - queue: [], - cancel: $delegate.cancel, - on: $delegate.on, - off: $delegate.off, - pin: $delegate.pin, - get reflows() { - return $$forceReflow.totalReflows; - }, - enabled: $delegate.enabled, - /** - * @ngdoc method - * @name $animate#closeAndFlush - * @description - * - * This method will close all pending animations (both {@link ngAnimate#javascript-based-animations Javascript} - * and {@link ngAnimate.$animateCss CSS}) and it will also flush any remaining animation frames and/or callbacks. - */ - closeAndFlush: function() { - // we allow the flush command to swallow the errors - // because depending on whether CSS or JS animations are - // used, there may not be a RAF flush. The primary flush - // at the end of this function must throw an exception - // because it will track if there were pending animations - this.flush(true); - $animateCss.$closeAndFlush(); - $$animateJs.$closeAndFlush(); - this.flush(); - }, - /** - * @ngdoc method - * @name $animate#flush - * @description - * - * This method is used to flush the pending callbacks and animation frames to either start - * an animation or conclude an animation. Note that this will not actually close an - * actively running animation (see {@link ngMock.$animate#closeAndFlush `closeAndFlush()`} for that). - */ - flush: function(hideErrors) { - $rootScope.$digest(); - - var doNextRun, somethingFlushed = false; - do { - doNextRun = false; - - if ($$rAF.queue.length) { - $$rAF.flush(); - doNextRun = somethingFlushed = true; - } - - if ($$animateAsyncRun.flush()) { - doNextRun = somethingFlushed = true; - } - } while (doNextRun); - - if (!somethingFlushed && !hideErrors) { - throw new Error('No pending animations ready to be closed or flushed'); - } - - $rootScope.$digest(); - } - }; - - angular.forEach( - ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) { - animate[method] = function() { - animate.queue.push({ - event: method, - element: arguments[0], - options: arguments[arguments.length - 1], - args: arguments - }); - return $delegate[method].apply($delegate, arguments); - }; - }); - - 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 service - * @name $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 [XHR](https://developer.mozilla.org/en/xmlhttprequest) or - * [JSONP](http://en.wikipedia.org/wiki/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 a 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 asynchronously. If we preserved - * this behavior in unit testing, we'd have to create async unit tests, which are hard to write, - * to follow and to maintain. But neither can the testing mock respond synchronously; 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. This preserves - * 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 when unit testing a controller. - * First we create the controller under test: - * - ```js - // The module code - angular - .module('MyApp', []) - .controller('MyController', MyController); - - // 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 = 'Failed...'; - }); - }; - } - ``` - * - * Now we setup the mock backend and create the test specs: - * - ```js - // testing controller - describe('MyController', function() { - var $httpBackend, $rootScope, createController, authRequestHandler; - - // Set up the module - beforeEach(module('MyApp')); - - beforeEach(inject(function($injector) { - // Set up the mock http service responses - $httpBackend = $injector.get('$httpBackend'); - // backend definition common for all tests - authRequestHandler = $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 fail authentication', function() { - - // Notice how you can change the response even after it was set - authRequestHandler.respond(401, ''); - - $httpBackend.expectGET('/auth.py'); - var controller = createController(); - $httpBackend.flush(); - expect($rootScope.status).toBe('Failed...'); - }); - - - 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 sent, 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', '$timeout', 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, $timeout, $delegate, $browser) { - var definitions = [], - expectations = [], - responses = [], - responsesPush = angular.bind(responses, responses.push), - copy = angular.copy; - - function createResponse(status, data, headers, statusText) { - if (angular.isFunction(status)) return status; - - return function() { - return angular.isNumber(status) - ? [status, data, headers, statusText] - : [200, status, data, headers]; - }; - } - - // TODO(vojta): change params to: method, url, data, headers, callback - function $httpBackend(method, url, data, callback, headers, timeout, withCredentials, responseType) { - - 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) : $timeout(handleTimeout, timeout); - } - - return handleResponse; - - function handleResponse() { - var response = wrapped.response(method, url, data, headers); - xhr.$$respHeaders = response[2]; - callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(), - copy(response[3] || '')); - } - - 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, responseType); - } 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 $httpBackend#when - * @description - * Creates a new backend definition. - * - * @param {string} method HTTP method. - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - * - * - respond – - * `{function([status,] data[, headers, statusText]) - * | 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), response - * headers (Object), and the text for the status (string). The respond method returns the - * `requestHandler` object for possible overrides. - */ - $httpBackend.when = function(method, url, data, headers) { - var definition = new MockHttpExpectation(method, url, data, headers), - chain = { - respond: function(status, data, headers, statusText) { - definition.passThrough = undefined; - definition.response = createResponse(status, data, headers, statusText); - return chain; - } - }; - - if ($browser) { - chain.passThrough = function() { - definition.response = undefined; - definition.passThrough = true; - return chain; - }; - } - - definitions.push(definition); - return chain; - }; - - /** - * @ngdoc method - * @name $httpBackend#whenGET - * @description - * Creates a new backend definition for GET requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @param {(Object|function(Object))=} headers HTTP headers. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#whenHEAD - * @description - * Creates a new backend definition for HEAD requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @param {(Object|function(Object))=} headers HTTP headers. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#whenDELETE - * @description - * Creates a new backend definition for DELETE requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @param {(Object|function(Object))=} headers HTTP headers. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#whenPOST - * @description - * Creates a new backend definition for POST requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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 controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#whenPUT - * @description - * Creates a new backend definition for PUT requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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 controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#whenJSONP - * @description - * Creates a new backend definition for JSONP requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - createShortMethods('when'); - - - /** - * @ngdoc method - * @name $httpBackend#expect - * @description - * Creates a new request expectation. - * - * @param {string} method HTTP method. - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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 controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - * - * - respond – - * `{function([status,] data[, headers, statusText]) - * | 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), response - * headers (Object), and the text for the status (string). The respond method returns the - * `requestHandler` object for possible overrides. - */ - $httpBackend.expect = function(method, url, data, headers) { - var expectation = new MockHttpExpectation(method, url, data, headers), - chain = { - respond: function(status, data, headers, statusText) { - expectation.response = createResponse(status, data, headers, statusText); - return chain; - } - }; - - expectations.push(expectation); - return chain; - }; - - - /** - * @ngdoc method - * @name $httpBackend#expectGET - * @description - * Creates a new request expectation for GET requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @param {Object=} headers HTTP headers. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. See #expect for more info. - */ - - /** - * @ngdoc method - * @name $httpBackend#expectHEAD - * @description - * Creates a new request expectation for HEAD requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @param {Object=} headers HTTP headers. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#expectDELETE - * @description - * Creates a new request expectation for DELETE requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @param {Object=} headers HTTP headers. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#expectPOST - * @description - * Creates a new request expectation for POST requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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 controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#expectPUT - * @description - * Creates a new request expectation for PUT requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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 controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#expectPATCH - * @description - * Creates a new request expectation for PATCH requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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 controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - - /** - * @ngdoc method - * @name $httpBackend#expectJSONP - * @description - * Creates a new request expectation for JSONP requests. For more info see `expect()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives an url - * and returns true if the url matches the current definition. - * @returns {requestHandler} Returns an object with `respond` method that controls how a matched - * request is handled. You can save this object for later use and invoke `respond` again in - * order to change how a matched request is handled. - */ - createShortMethods('expect'); - - - /** - * @ngdoc method - * @name $httpBackend#flush - * @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, digest) { - if (digest !== false) $rootScope.$digest(); - if (!responses.length) throw new Error('No pending request to flush !'); - - if (angular.isDefined(count) && count !== null) { - while (count--) { - if (!responses.length) throw new Error('No more pending request to flush !'); - responses.shift()(); - } - } else { - while (responses.length) { - responses.shift()(); - } - } - $httpBackend.verifyNoOutstandingExpectation(digest); - }; - - - /** - * @ngdoc method - * @name $httpBackend#verifyNoOutstandingExpectation - * @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. - * - * ```js - * afterEach($httpBackend.verifyNoOutstandingExpectation); - * ``` - */ - $httpBackend.verifyNoOutstandingExpectation = function(digest) { - if (digest !== false) $rootScope.$digest(); - if (expectations.length) { - throw new Error('Unsatisfied requests: ' + expectations.join(', ')); - } - }; - - - /** - * @ngdoc method - * @name $httpBackend#verifyNoOutstandingRequest - * @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. - * - * ```js - * afterEach($httpBackend.verifyNoOutstandingRequest); - * ``` - */ - $httpBackend.verifyNoOutstandingRequest = function() { - if (responses.length) { - throw new Error('Unflushed requests: ' + responses.length); - } - }; - - - /** - * @ngdoc method - * @name $httpBackend#resetExpectations - * @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', 'HEAD'], 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); - if (angular.isFunction(url)) return url(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(angular.fromJson(angular.toJson(data)), angular.fromJson(d)); - } - return data == d; - }; - - this.toString = function() { - return method + ' ' + url; - }; -} - -function createMockXhr() { - return new MockXhr(); -} - -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 service - * @name $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 = ['$delegate', '$browser', function($delegate, $browser) { - - /** - * @ngdoc method - * @name $timeout#flush - * @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 $timeout#verifyNoPendingTasks - * @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.$RAFDecorator = ['$delegate', function($delegate) { - var rafFn = function(fn) { - var index = rafFn.queue.length; - rafFn.queue.push(fn); - return function() { - rafFn.queue.splice(index, 1); - }; - }; - - rafFn.queue = []; - rafFn.supported = $delegate.supported; - - rafFn.flush = function() { - if (rafFn.queue.length === 0) { - throw new Error('No rAF callbacks present'); - } - - var length = rafFn.queue.length; - for (var i = 0; i < length; i++) { - rafFn.queue[i](); - } - - rafFn.queue = rafFn.queue.slice(i); - }; - - return rafFn; -}]; - -/** - * - */ -angular.mock.$RootElementProvider = function() { - this.$get = function() { - return angular.element('
'); - }; -}; - -/** - * @ngdoc service - * @name $controller - * @description - * A decorator for {@link ng.$controller} with additional `bindings` parameter, useful when testing - * controllers of directives that use {@link $compile#-bindtocontroller- `bindToController`}. - * - * - * ## Example - * - * ```js - * - * // Directive definition ... - * - * myMod.directive('myDirective', { - * controller: 'MyDirectiveController', - * bindToController: { - * name: '@' - * } - * }); - * - * - * // Controller definition ... - * - * myMod.controller('MyDirectiveController', ['$log', function($log) { - * $log.info(this.name); - * }]); - * - * - * // In a test ... - * - * describe('myDirectiveController', function() { - * it('should write the bound name to the log', inject(function($controller, $log) { - * var ctrl = $controller('MyDirectiveController', { /* no locals */ }, { name: 'Clark Kent' }); - * expect(ctrl.name).toEqual('Clark Kent'); - * expect($log.info.logs).toEqual(['Clark Kent']); - * })); - * }); - * - * ``` - * - * @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 - * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global - * `window` object (not recommended) - * - * The string can use the `controller as property` syntax, where the controller instance is published - * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this - * to work correctly. - * - * @param {Object} locals Injection locals for Controller. - * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used - * to simulate the `bindToController` feature and simplify certain kinds of tests. - * @return {Object} Instance of given controller. - */ -angular.mock.$ControllerDecorator = ['$delegate', function($delegate) { - return function(expression, locals, later, ident) { - if (later && typeof later === 'object') { - var create = $delegate(expression, locals, true, ident); - angular.extend(create.instance, later); - return create(); - } - return $delegate(expression, locals, later, ident); - }; -}]; - - -/** - * @ngdoc module - * @name ngMock - * @packageName angular-mocks - * @description - * - * # ngMock - * - * The `ngMock` module provides 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. - * - * - *
- * - */ -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); - $provide.decorator('$$rAF', angular.mock.$RAFDecorator); - $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator); - $provide.decorator('$controller', angular.mock.$ControllerDecorator); -}]); - -/** - * @ngdoc module - * @name ngMockE2E - * @module ngMockE2E - * @packageName angular-mocks - * @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 service - * @name $httpBackend - * @module ngMockE2E - * @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 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: - * - * ```js - * 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) { - * var phone = angular.fromJson(data); - * phones.push(phone); - * return [200, phone, {}]; - * }); - * $httpBackend.whenGET(/^\/templates\//).passThrough(); - * //... - * }); - * ``` - * - * Afterwards, bootstrap your app with this new module. - */ - -/** - * @ngdoc method - * @name $httpBackend#when - * @module ngMockE2E - * @description - * Creates a new backend definition. - * - * @param {string} method HTTP method. - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - * - * - respond – - * `{function([status,] data[, headers, statusText]) - * | 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), response headers - * (Object), and the text for the status (string). - * - passThrough – `{function()}` – Any request matching a backend definition with - * `passThrough` handler will be passed through to the real backend (an XHR request will be made - * to the server.) - * - Both methods return the `requestHandler` object for possible overrides. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenGET - * @module ngMockE2E - * @description - * Creates a new backend definition for GET requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenHEAD - * @module ngMockE2E - * @description - * Creates a new backend definition for HEAD requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenDELETE - * @module ngMockE2E - * @description - * Creates a new backend definition for DELETE requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenPOST - * @module ngMockE2E - * @description - * Creates a new backend definition for POST requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenPUT - * @module ngMockE2E - * @description - * Creates a new backend definition for PUT requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenPATCH - * @module ngMockE2E - * @description - * Creates a new backend definition for PATCH requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @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. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ - -/** - * @ngdoc method - * @name $httpBackend#whenJSONP - * @module ngMockE2E - * @description - * Creates a new backend definition for JSONP requests. For more info see `when()`. - * - * @param {string|RegExp|function(string)} url HTTP url or function that receives a url - * and returns true if the url matches the current definition. - * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that - * control how a matched request is handled. You can save this object for later use and invoke - * `respond` or `passThrough` again in order to change how a matched request is handled. - */ -angular.mock.e2e = {}; -angular.mock.e2e.$httpBackendDecorator = - ['$rootScope', '$timeout', '$delegate', '$browser', createHttpBackendMock]; - - -/** - * @ngdoc type - * @name $rootScope.Scope - * @module ngMock - * @description - * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These - * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when - * `ngMock` module is loaded. - * - * In addition to all the regular `Scope` methods, the following helper methods are available: - */ -angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) { - - var $rootScopePrototype = Object.getPrototypeOf($delegate); - - $rootScopePrototype.$countChildScopes = countChildScopes; - $rootScopePrototype.$countWatchers = countWatchers; - - return $delegate; - - // ------------------------------------------------------------------------------------------ // - - /** - * @ngdoc method - * @name $rootScope.Scope#$countChildScopes - * @module ngMock - * @description - * Counts all the direct and indirect child scopes of the current scope. - * - * The current scope is excluded from the count. The count includes all isolate child scopes. - * - * @returns {number} Total number of child scopes. - */ - function countChildScopes() { - // jshint validthis: true - var count = 0; // exclude the current scope - var pendingChildHeads = [this.$$childHead]; - var currentScope; - - while (pendingChildHeads.length) { - currentScope = pendingChildHeads.shift(); - - while (currentScope) { - count += 1; - pendingChildHeads.push(currentScope.$$childHead); - currentScope = currentScope.$$nextSibling; - } - } - - return count; - } - - - /** - * @ngdoc method - * @name $rootScope.Scope#$countWatchers - * @module ngMock - * @description - * Counts all the watchers of direct and indirect child scopes of the current scope. - * - * The watchers of the current scope are included in the count and so are all the watchers of - * isolate child scopes. - * - * @returns {number} Total number of watchers. - */ - function countWatchers() { - // jshint validthis: true - var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope - var pendingChildHeads = [this.$$childHead]; - var currentScope; - - while (pendingChildHeads.length) { - currentScope = pendingChildHeads.shift(); - - while (currentScope) { - count += currentScope.$$watchers ? currentScope.$$watchers.length : 0; - pendingChildHeads.push(currentScope.$$childHead); - currentScope = currentScope.$$nextSibling; - } - } - - return count; - } -}]; - - -if (window.jasmine || window.mocha) { - - var currentSpec = null, - annotatedFunctions = [], - isSpecRunning = function() { - return !!currentSpec; - }; - - angular.mock.$$annotate = angular.injector.$$annotate; - angular.injector.$$annotate = function(fn) { - if (typeof fn === 'function' && !fn.$inject) { - annotatedFunctions.push(fn); - } - return angular.mock.$$annotate.apply(this, arguments); - }; - - - (window.beforeEach || window.setup)(function() { - annotatedFunctions = []; - currentSpec = this; - }); - - (window.afterEach || window.teardown)(function() { - var injector = currentSpec.$injector; - - annotatedFunctions.forEach(function(fn) { - delete fn.$inject; - }); - - angular.forEach(currentSpec.$modules, function(module) { - if (module && module.$$hashKey) { - module.$$hashKey = undefined; - } - }); - - currentSpec.$injector = null; - currentSpec.$modules = null; - currentSpec = null; - - if (injector) { - injector.get('$rootElement').off(); - } - - // 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.
- * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha - * - * 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 each key-value pair will be registered on the module via - * {@link auto.$provide $provide}.value, the key being the string name (or token) to associate - * with the value on the injector. - */ - 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.
- * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha - * - * 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. - * ```js - * - * 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. - */ - - - - var ErrorAddingDeclarationLocationStack = function(e, errorForStack) { - this.message = e.message; - this.name = e.name; - if (e.line) this.line = e.line; - if (e.sourceId) this.sourceId = e.sourceId; - if (e.stack && errorForStack) - this.stack = e.stack + '\n' + errorForStack.stack; - if (e.stackArray) this.stackArray = e.stackArray; - }; - ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString; - - window.inject = angular.mock.inject = function() { - var blockFns = Array.prototype.slice.call(arguments, 0); - var errorForStack = new Error('Declaration Location'); - return isSpecRunning() ? workFn.call(currentSpec) : workFn; - ///////////////////// - function workFn() { - var modules = currentSpec.$modules || []; - var strictDi = !!currentSpec.$injectorStrict; - modules.unshift('ngMock'); - modules.unshift('ng'); - var injector = currentSpec.$injector; - if (!injector) { - if (strictDi) { - // If strictDi is enabled, annotate the providerInjector blocks - angular.forEach(modules, function(moduleFn) { - if (typeof moduleFn === "function") { - angular.injector.$$annotate(moduleFn); - } - }); - } - injector = currentSpec.$injector = angular.injector(modules, strictDi); - currentSpec.$injectorStrict = strictDi; - } - for (var i = 0, ii = blockFns.length; i < ii; i++) { - if (currentSpec.$injectorStrict) { - // If the injector is strict / strictDi, and the spec wants to inject using automatic - // annotation, then annotate the function here. - injector.annotate(blockFns[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) { - throw new ErrorAddingDeclarationLocationStack(e, errorForStack); - } - throw e; - } finally { - errorForStack = null; - } - } - } - }; - - - angular.mock.inject.strictDi = function(value) { - value = arguments.length ? !!value : true; - return isSpecRunning() ? workFn() : workFn; - - function workFn() { - if (value !== currentSpec.$injectorStrict) { - if (currentSpec.$injector) { - throw new Error('Injector already created, can not modify strict annotations'); - } else { - currentSpec.$injectorStrict = value; - } - } - } - }; -} - - -})(window, window.angular); - -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { - self.lastNotificationId = _.last(notifications).id; - } - - _.each(notifications, function(notification) { - self.emit('notification', notification); - }); - return cb(); - }); -}; - -API.prototype._initNotifications = function(opts) { - var self = this; - - opts = opts || {}; - - var interval = opts.notificationIntervalSeconds || 5; - self.notificationsIntervalId = setInterval(function() { - self._fetchLatestNotifications(interval, function(err) { - if (err) { - if (err instanceof Errors.NOT_FOUND || err instanceof Errors.NOT_AUTHORIZED) { - self._disposeNotifications(); - } - } - }); - }, interval * 1000); -}; - -API.prototype._disposeNotifications = function() { - var self = this; - - if (self.notificationsIntervalId) { - clearInterval(self.notificationsIntervalId); - self.notificationsIntervalId = null; - } -}; - - -/** - * Reset notification polling with new interval - * @param {Numeric} notificationIntervalSeconds - use 0 to pause notifications - */ -API.prototype.setNotificationsInterval = function(notificationIntervalSeconds) { - var self = this; - self._disposeNotifications(); - if (notificationIntervalSeconds > 0) { - self._initNotifications({ - notificationIntervalSeconds: notificationIntervalSeconds - }); - } -}; - - -/** - * Encrypt a message - * @private - * @static - * @memberof Client.API - * @param {String} message - * @param {String} encryptingKey - */ -API._encryptMessage = function(message, encryptingKey) { - if (!message) return null; - return Utils.encryptMessage(message, encryptingKey); -}; - -/** - * Decrypt a message - * @private - * @static - * @memberof Client.API - * @param {String} message - * @param {String} encryptingKey - */ -API._decryptMessage = function(message, encryptingKey) { - if (!message) return ''; - try { - return Utils.decryptMessage(message, encryptingKey); - } catch (ex) { - return ''; - } -}; - -API.prototype._processTxNotes = function(notes) { - var self = this; - - if (!notes) return; - - var encryptingKey = self.credentials.sharedEncryptingKey; - _.each([].concat(notes), function(note) { - note.encryptedBody = note.body; - note.body = API._decryptMessage(note.body, encryptingKey); - note.encryptedEditedByName = note.editedByName; - note.editedByName = API._decryptMessage(note.editedByName, encryptingKey); - }); -}; - -/** - * Decrypt text fields in transaction proposals - * @private - * @static - * @memberof Client.API - * @param {Array} txps - * @param {String} encryptingKey - */ -API.prototype._processTxps = function(txps) { - var self = this; - if (!txps) return; - - var encryptingKey = self.credentials.sharedEncryptingKey; - _.each([].concat(txps), function(txp) { - txp.encryptedMessage = txp.message; - txp.message = API._decryptMessage(txp.message, encryptingKey) || null; - txp.creatorName = API._decryptMessage(txp.creatorName, encryptingKey); - - _.each(txp.actions, function(action) { - action.copayerName = API._decryptMessage(action.copayerName, encryptingKey); - action.comment = API._decryptMessage(action.comment, encryptingKey); - // TODO get copayerName from Credentials -> copayerId to copayerName - // action.copayerName = null; - }); - _.each(txp.outputs, function(output) { - output.encryptedMessage = output.message; - output.message = API._decryptMessage(output.message, encryptingKey) || null; - }); - txp.hasUnconfirmedInputs = _.any(txp.inputs, function(input) { - return input.confirmations == 0; - }); - self._processTxNotes(txp.note); - }); -}; - -/** - * Parse errors - * @private - * @static - * @memberof Client.API - * @param {Object} body - */ -API._parseError = function(body) { - if (_.isString(body)) { - try { - body = JSON.parse(body); - } catch (e) { - body = { - error: body - }; - } - } - var ret; - if (body && body.code) { - if (Errors[body.code]) { - ret = new Errors[body.code]; - } else { - ret = new Error(body.code); - } - } else { - ret = new Error(body.error || body); - } - log.error(ret); - return ret; -}; - -/** - * Sign an HTTP request - * @private - * @static - * @memberof Client.API - * @param {String} method - The HTTP method - * @param {String} url - The URL for the request - * @param {Object} args - The arguments in case this is a POST/PUT request - * @param {String} privKey - Private key to sign the request - */ -API._signRequest = function(method, url, args, privKey) { - var message = [method.toLowerCase(), url, JSON.stringify(args)].join('|'); - return Utils.signMessage(message, privKey); -}; - - -/** - * Seed from random - * - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - */ -API.prototype.seedFromRandom = function(opts) { - $.checkArgument(arguments.length <= 1, 'DEPRECATED: only 1 argument accepted.'); - $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: argument should be an options object.'); - - opts = opts || {}; - this.credentials = Credentials.create(opts.network || 'livenet'); -}; - - -var _deviceValidated; - -/** - * Seed from random - * - * @param {Object} opts - * @param {String} opts.passphrase - * @param {String} opts.skipDeviceValidation - */ -API.prototype.validateKeyDerivation = function(opts, cb) { - var self = this; - - opts = opts || {}; - - var c = self.credentials; - - function testMessageSigning(xpriv, xpub) { - var nonHardenedPath = 'm/0/0'; - var message = 'Lorem ipsum dolor sit amet, ne amet urbanitas percipitur vim, libris disputando his ne, et facer suavitate qui. Ei quidam laoreet sea. Cu pro dico aliquip gubergren, in mundi postea usu. Ad labitur posidonium interesset duo, est et doctus molestie adipiscing.'; - var priv = xpriv.derive(nonHardenedPath).privateKey; - var signature = Utils.signMessage(message, priv); - var pub = xpub.derive(nonHardenedPath).publicKey; - return Utils.verifyMessage(message, signature, pub); - }; - - function testHardcodedKeys() { - var words = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; - var xpriv = Mnemonic(words).toHDPrivateKey(); - - if (xpriv.toString() != 'xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu') return false; - - xpriv = xpriv.derive("m/44'/0'/0'"); - if (xpriv.toString() != 'xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb') return false; - - var xpub = Bitcore.HDPublicKey.fromString('xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj'); - return testMessageSigning(xpriv, xpub); - }; - - function testLiveKeys() { - var words; - try { - words = c.getMnemonic(); - } catch (ex) {} - - var xpriv; - if (words && (!c.mnemonicHasPassphrase || opts.passphrase)) { - var m = new Mnemonic(words); - xpriv = m.toHDPrivateKey(opts.passphrase, c.network); - } - if (!xpriv) { - xpriv = new Bitcore.HDPrivateKey(c.xPrivKey); - } - xpriv = xpriv.derive(c.getBaseAddressDerivationPath()); - var xpub = new Bitcore.HDPublicKey(c.xPubKey); - - return testMessageSigning(xpriv, xpub); - }; - - var hardcodedOk = true; - if (!_deviceValidated && !opts.skipDeviceValidation) { - hardcodedOk = testHardcodedKeys(); - _deviceValidated = true; - } - - var liveOk = (c.canSign() && !c.isPrivKeyEncrypted()) ? testLiveKeys() : true; - - self.keyDerivationOk = hardcodedOk && liveOk; - - return cb(null, self.keyDerivationOk); -}; - -/** - * Seed from random with mnemonic - * - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - * @param {String} opts.passphrase - * @param {Number} opts.language - default 'en' - * @param {Number} opts.account - default 0 - */ -API.prototype.seedFromRandomWithMnemonic = function(opts) { - $.checkArgument(arguments.length <= 1, 'DEPRECATED: only 1 argument accepted.'); - $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: argument should be an options object.'); - - opts = opts || {}; - this.credentials = Credentials.createWithMnemonic(opts.network || 'livenet', opts.passphrase, opts.language || 'en', opts.account || 0); -}; - -API.prototype.getMnemonic = function() { - return this.credentials.getMnemonic(); -}; - -API.prototype.mnemonicHasPassphrase = function() { - return this.credentials.mnemonicHasPassphrase; -}; - - - -API.prototype.clearMnemonic = function() { - return this.credentials.clearMnemonic(); -}; - - -/** - * Seed from extended private key - * - * @param {String} xPrivKey - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.seedFromExtendedPrivateKey = function(xPrivKey, opts) { - opts = opts || {}; - this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); -}; - - -/** - * Seed from Mnemonics (language autodetected) - * Can throw an error if mnemonic is invalid - * - * @param {String} BIP39 words - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - * @param {String} opts.passphrase - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.seedFromMnemonic = function(words, opts) { - $.checkArgument(_.isUndefined(opts) || _.isObject(opts), 'DEPRECATED: second argument should be an options object.'); - - opts = opts || {}; - this.credentials = Credentials.fromMnemonic(opts.network || 'livenet', words, opts.passphrase, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); -}; - -/** - * Seed from external wallet public key - * - * @param {String} xPubKey - * @param {String} source - A name identifying the source of the xPrivKey (e.g. ledger, TREZOR, ...) - * @param {String} entropySourceHex - A HEX string containing pseudo-random data, that can be deterministically derived from the xPrivKey, and should not be derived from xPubKey. - * @param {Object} opts - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.seedFromExtendedPublicKey = function(xPubKey, source, entropySourceHex, opts) { - $.checkArgument(_.isUndefined(opts) || _.isObject(opts)); - - opts = opts || {}; - this.credentials = Credentials.fromExtendedPublicKey(xPubKey, source, entropySourceHex, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); -}; - - -/** - * Export wallet - * - * @param {Object} opts - * @param {Boolean} opts.noSign - */ -API.prototype.export = function(opts) { - $.checkState(this.credentials); - - opts = opts || {}; - - var output; - - var c = Credentials.fromObj(this.credentials); - - if (opts.noSign) { - c.setNoSign(); - } - - output = JSON.stringify(c.toObj()); - - return output; -}; - - -/** - * Import wallet - * emits 'derivation-error' in case keys are not validated correctly. - * - * @param {Object} str - * @param {Object} opts - * @param {String} opts.password If the source has the private key encrypted, the password - * will be needed for derive credentials fields. - */ -API.prototype.import = function(str, opts) { - opts = opts || {}; - try { - var credentials = Credentials.fromObj(JSON.parse(str)); - this.credentials = credentials; - } catch (ex) { - throw new Errors.INVALID_BACKUP; - } -}; - -API.prototype._import = function(cb) { - $.checkState(this.credentials); - - var self = this; - - // First option, grab wallet info from BWS. - self.openWallet(function(err, ret) { - - // it worked? - if (!err) return cb(null, ret); - - // Is the error other than "copayer was not found"? || or no priv key. - if (err instanceof Errors.NOT_AUTHORIZED || self.isPrivKeyExternal()) - return cb(err); - - //Second option, lets try to add an access - log.info('Copayer not found, trying to add access'); - self.addAccess({}, function(err) { - if (err) { - return cb(new Errors.WALLET_DOES_NOT_EXIST); - } - - self.openWallet(cb); - }); - }); -}; - -/** - * Import from Mnemonics (language autodetected) - * Can throw an error if mnemonic is invalid - * - * @param {String} BIP39 words - * @param {Object} opts - * @param {String} opts.network - default 'livenet' - * @param {String} opts.passphrase - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.importFromMnemonic = function(words, opts, cb) { - log.debug('Importing from 12 Words'); - - opts = opts || {}; - try { - this.credentials = Credentials.fromMnemonic(opts.network || 'livenet', words, opts.passphrase, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); - } catch (e) { - log.info('Mnemonic error:', e); - return cb(new Errors.INVALID_BACKUP); - }; - - this._import(cb); -}; - -/* - * Import from extended private key - * - * @param {String} xPrivKey - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - * @param {Callback} cb - The callback that handles the response. It returns a flag indicating that the wallet is imported. - */ -API.prototype.importFromExtendedPrivateKey = function(xPrivKey, opts, cb) { - log.debug('Importing from Extended Private Key'); - - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: importFromExtendedPrivateKey should receive 3 parameters.'); - } - - try { - this.credentials = Credentials.fromExtendedPrivateKey(xPrivKey, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); - } catch (e) { - log.info('xPriv error:', e); - return cb(new Errors.INVALID_BACKUP); - }; - - this._import(cb); -}; - -/** - * Import from Extended Public Key - * - * @param {String} xPubKey - * @param {String} source - A name identifying the source of the xPrivKey - * @param {String} entropySourceHex - A HEX string containing pseudo-random data, that can be deterministically derived from the xPrivKey, and should not be derived from xPubKey. - * @param {Object} opts - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - */ -API.prototype.importFromExtendedPublicKey = function(xPubKey, source, entropySourceHex, opts, cb) { - $.checkArgument(arguments.length == 5, "DEPRECATED: should receive 5 arguments"); - $.checkArgument(_.isUndefined(opts) || _.isObject(opts)); - $.shouldBeFunction(cb); - - opts = opts || {}; - log.debug('Importing from Extended Private Key'); - try { - this.credentials = Credentials.fromExtendedPublicKey(xPubKey, source, entropySourceHex, opts.account || 0, opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP44); - } catch (e) { - log.info('xPriv error:', e); - return cb(new Errors.INVALID_BACKUP); - }; - - this._import(cb); -}; - -API.prototype.decryptBIP38PrivateKey = function(encryptedPrivateKeyBase58, passphrase, opts, cb) { - var Bip38 = require('bip38'); - var bip38 = new Bip38(); - - var privateKeyWif; - try { - privateKeyWif = bip38.decrypt(encryptedPrivateKeyBase58, passphrase); - } catch (ex) { - return cb(new Error('Could not decrypt BIP38 private key', ex)); - } - - var privateKey = new Bitcore.PrivateKey(privateKeyWif); - var address = privateKey.publicKey.toAddress().toString(); - var addrBuff = new Buffer(address, 'ascii'); - var actualChecksum = Bitcore.crypto.Hash.sha256sha256(addrBuff).toString('hex').substring(0, 8); - var expectedChecksum = Bitcore.encoding.Base58Check.decode(encryptedPrivateKeyBase58).toString('hex').substring(6, 14); - - if (actualChecksum != expectedChecksum) - return cb(new Error('Incorrect passphrase')); - - return cb(null, privateKeyWif); -}; - -API.prototype.getBalanceFromPrivateKey = function(privateKey, cb) { - var self = this; - - var privateKey = new Bitcore.PrivateKey(privateKey); - var address = privateKey.publicKey.toAddress(); - self.getUtxos({ - addresses: address.toString(), - }, function(err, utxos) { - if (err) return cb(err); - return cb(null, _.sum(utxos, 'satoshis')); - }); -}; - -API.prototype.buildTxFromPrivateKey = function(privateKey, destinationAddress, opts, cb) { - var self = this; - - opts = opts || {}; - - var privateKey = new Bitcore.PrivateKey(privateKey); - var address = privateKey.publicKey.toAddress(); - - async.waterfall([ - - function(next) { - self.getUtxos({ - addresses: address.toString(), - }, function(err, utxos) { - return next(err, utxos); - }); - }, - function(utxos, next) { - if (!_.isArray(utxos) || utxos.length == 0) return next(new Error('No utxos found')); - - var fee = opts.fee || 10000; - var amount = _.sum(utxos, 'satoshis') - fee; - if (amount <= 0) return next(new Errors.INSUFFICIENT_FUNDS); - - var tx; - try { - var toAddress = Bitcore.Address.fromString(destinationAddress); - - tx = new Bitcore.Transaction() - .from(utxos) - .to(toAddress, amount) - .fee(fee) - .sign(privateKey); - - // Make sure the tx can be serialized - tx.serialize(); - - } catch (ex) { - log.error('Could not build transaction from private key', ex); - return next(new Errors.COULD_NOT_BUILD_TRANSACTION); - } - return next(null, tx); - } - ], cb); -}; - -/** - * Open a wallet and try to complete the public key ring. - * - * @param {Callback} cb - The callback that handles the response. It returns a flag indicating that the wallet is complete. - * @fires API#walletCompleted - */ -API.prototype.openWallet = function(cb) { - $.checkState(this.credentials); - var self = this; - if (self.credentials.isComplete() && self.credentials.hasWalletInfo()) - return cb(null, true); - - self._doGetRequest('/v2/wallets/?includeExtendedInfo=1', function(err, ret) { - if (err) return cb(err); - var wallet = ret.wallet; - - self._processStatus(ret); - - if (!self.credentials.hasWalletInfo()) { - var me = _.find(wallet.copayers, { - id: self.credentials.copayerId - }); - self.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, me.name); - } - - if (wallet.status != 'complete') - return cb(); - - if (self.credentials.walletPrivKey) { - if (!Verifier.checkCopayers(self.credentials, wallet.copayers)) { - return cb(new Errors.SERVER_COMPROMISED); - } - } else { - // this should only happen in AIR-GAPPED flows - log.warn('Could not verify copayers key (missing wallet Private Key)'); - } - - self.credentials.addPublicKeyRing(API._extractPublicKeyRing(wallet.copayers)); - - self.emit('walletCompleted', wallet); - - return cb(null, ret); - }); -}; - - -API.prototype._getHeaders = function(method, url, args) { - var headers = { - 'x-client-version': 'bwc-' + Package.version, - }; - - if (this.credentials) { - var reqSignature; - var key = args._requestPrivKey || this.credentials.requestPrivKey; - if (key) { - delete args['_requestPrivKey']; - reqSignature = API._signRequest(method, url, args, key); - } - headers['x-identity'] = this.credentials.copayerId; - headers['x-signature'] = reqSignature; - } - return headers; -} - - - -/** - * Do an HTTP request - * @private - * - * @param {Object} method - * @param {String} url - * @param {Object} args - * @param {Callback} cb - */ -API.prototype._doRequest = function(method, url, args, cb) { - var absUrl = this.baseUrl + url; - var newArgs = { - // relUrl: only for testing with `supertest` - relUrl: this.basePath + url, - headers: this._getHeaders(method, url, args), - method: method, - url: absUrl, - body: args, - json: true, - withCredentials: false, - timeout: this.timeout, - }; - - log.debug('Request Args', util.inspect(args, { - depth: 10 - })); - - this.request(newArgs, function(err, res, body) { - log.debug(util.inspect(body, { - depth: 10 - })); - if (!res) { - return cb(new Errors.CONNECTION_ERROR); - } - - if (res.statusCode !== 200) { - if (res.statusCode === 404) - return cb(new Errors.NOT_FOUND); - - if (!res.statusCode) - return cb(new Errors.CONNECTION_ERROR); - - return cb(API._parseError(body)); - } - - if (body === '{"error":"read ECONNRESET"}') - return cb(new Errors.ECONNRESET_ERROR(JSON.parse(body))); - - return cb(null, body, res.header); - }); -}; - -/** - * Do a POST request - * @private - * - * @param {String} url - * @param {Object} args - * @param {Callback} cb - */ -API.prototype._doPostRequest = function(url, args, cb) { - return this._doRequest('post', url, args, cb); -}; - -API.prototype._doPutRequest = function(url, args, cb) { - return this._doRequest('put', url, args, cb); -}; - -/** - * Do a GET request - * @private - * - * @param {String} url - * @param {Callback} cb - */ -API.prototype._doGetRequest = function(url, cb) { - url += url.indexOf('?') > 0 ? '&' : '?'; - url += 'r=' + _.random(10000, 99999); - return this._doRequest('get', url, {}, cb); -}; - -/** - * Do a DELETE request - * @private - * - * @param {String} url - * @param {Callback} cb - */ -API.prototype._doDeleteRequest = function(url, cb) { - return this._doRequest('delete', url, {}, cb); -}; - -API._buildSecret = function(walletId, walletPrivKey, network) { - if (_.isString(walletPrivKey)) { - walletPrivKey = Bitcore.PrivateKey.fromString(walletPrivKey); - } - var widHex = new Buffer(walletId.replace(/-/g, ''), 'hex'); - var widBase58 = new Bitcore.encoding.Base58(widHex).toString(); - return _.padRight(widBase58, 22, '0') + walletPrivKey.toWIF() + (network == 'testnet' ? 'T' : 'L'); -}; - -API.parseSecret = function(secret) { - $.checkArgument(secret); - - function split(str, indexes) { - var parts = []; - indexes.push(str.length); - var i = 0; - while (i < indexes.length) { - parts.push(str.substring(i == 0 ? 0 : indexes[i - 1], indexes[i])); - i++; - }; - return parts; - }; - - try { - var secretSplit = split(secret, [22, 74]); - var widBase58 = secretSplit[0].replace(/0/g, ''); - var widHex = Bitcore.encoding.Base58.decode(widBase58).toString('hex'); - var walletId = split(widHex, [8, 12, 16, 20]).join('-'); - - var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]); - var networkChar = secretSplit[2]; - - return { - walletId: walletId, - walletPrivKey: walletPrivKey, - network: networkChar == 'T' ? 'testnet' : 'livenet', - }; - } catch (ex) { - throw new Error('Invalid secret'); - } -}; - -API.getRawTx = function(txp) { - var t = Utils.buildTx(txp); - return t.uncheckedSerialize(); -}; - -API.signTxp = function(txp, derivedXPrivKey) { - //Derive proper key to sign, for each input - var privs = []; - var derived = {}; - - var xpriv = new Bitcore.HDPrivateKey(derivedXPrivKey); - - _.each(txp.inputs, function(i) { - $.checkState(i.path, "Input derivation path no available (signing transaction)") - if (!derived[i.path]) { - derived[i.path] = xpriv.derive(i.path).privateKey; - privs.push(derived[i.path]); - } - }); - - var t = Utils.buildTx(txp); - - var signatures = _.map(privs, function(priv, i) { - return t.getSignatures(priv); - }); - - signatures = _.map(_.sortBy(_.flatten(signatures), 'inputIndex'), function(s) { - return s.signature.toDER().toString('hex'); - }); - - return signatures; -}; - -API.prototype._signTxp = function(txp) { - return API.signTxp(txp, this.credentials.getDerivedXPrivKey()); -}; - -API.prototype._getCurrentSignatures = function(txp) { - var acceptedActions = _.filter(txp.actions, { - type: 'accept' - }); - - return _.map(acceptedActions, function(x) { - return { - signatures: x.signatures, - xpub: x.xpub, - }; - }); -}; - -API.prototype._addSignaturesToBitcoreTx = function(txp, t, signatures, xpub) { - if (signatures.length != txp.inputs.length) - throw new Error('Number of signatures does not match number of inputs'); - - var i = 0, - x = new Bitcore.HDPublicKey(xpub); - - _.each(signatures, function(signatureHex) { - var input = txp.inputs[i]; - try { - var signature = Bitcore.crypto.Signature.fromString(signatureHex); - var pub = x.derive(txp.inputPaths[i]).publicKey; - var s = { - inputIndex: i, - signature: signature, - sigtype: Bitcore.crypto.Signature.SIGHASH_ALL, - publicKey: pub, - }; - t.inputs[i].addSignature(t, s); - i++; - } catch (e) {}; - }); - - if (i != txp.inputs.length) - throw new Error('Wrong signatures'); -}; - - -API.prototype._applyAllSignatures = function(txp, t) { - var self = this; - - $.checkState(txp.status == 'accepted'); - - var sigs = self._getCurrentSignatures(txp); - _.each(sigs, function(x) { - self._addSignaturesToBitcoreTx(txp, t, x.signatures, x.xpub); - }); -}; - -/** - * Join - * @private - * - * @param {String} walletId - * @param {String} walletPrivKey - * @param {String} xPubKey - * @param {String} requestPubKey - * @param {String} copayerName - * @param {Object} Optional args - * @param {String} opts.customData - * @param {Callback} cb - */ -API.prototype._doJoinWallet = function(walletId, walletPrivKey, xPubKey, requestPubKey, copayerName, opts, cb) { - $.shouldBeFunction(cb); - var self = this; - - opts = opts || {}; - - // Adds encrypted walletPrivateKey to CustomData - opts.customData = opts.customData || {}; - opts.customData.walletPrivKey = walletPrivKey.toString(); - var encCustomData = Utils.encryptMessage(JSON.stringify(opts.customData), this.credentials.personalEncryptingKey); - var encCopayerName = Utils.encryptMessage(copayerName, this.credentials.sharedEncryptingKey); - - var args = { - walletId: walletId, - name: encCopayerName, - xPubKey: xPubKey, - requestPubKey: requestPubKey, - customData: encCustomData, - }; - if (opts.dryRun) args.dryRun = true; - - if (_.isBoolean(opts.supportBIP44AndP2PKH)) - args.supportBIP44AndP2PKH = opts.supportBIP44AndP2PKH; - - var hash = Utils.getCopayerHash(args.name, args.xPubKey, args.requestPubKey); - args.copayerSignature = Utils.signMessage(hash, walletPrivKey); - - var url = '/v2/wallets/' + walletId + '/copayers'; - this._doPostRequest(url, args, function(err, body) { - if (err) return cb(err); - self._processWallet(body.wallet); - return cb(null, body.wallet); - }); -}; - -/** - * Return if wallet is complete - */ -API.prototype.isComplete = function() { - return this.credentials && this.credentials.isComplete(); -}; - -/** - * Is private key currently encrypted? (ie, locked) - * - * @return {Boolean} - */ -API.prototype.isPrivKeyEncrypted = function() { - return this.credentials && this.credentials.isPrivKeyEncrypted(); -}; - -/** - * Is private key encryption setup? - * - * @return {Boolean} - */ -API.prototype.hasPrivKeyEncrypted = function() { - return this.credentials && this.credentials.hasPrivKeyEncrypted(); -}; - -/** - * Is private key external? - * - * @return {Boolean} - */ -API.prototype.isPrivKeyExternal = function() { - return this.credentials && this.credentials.hasExternalSource(); -}; - -/** - * Get external wallet source name - * - * @return {String} - */ -API.prototype.getPrivKeyExternalSourceName = function() { - return this.credentials ? this.credentials.getExternalSourceName() : null; -}; - -/** - * unlocks the private key. `lock` need to be called explicity - * later to remove the unencrypted private key. - * - * @param password - */ -API.prototype.unlock = function(password) { - try { - this.credentials.unlock(password); - } catch (e) { - throw new Error('Could not unlock:' + e); - } -}; - -/** - * Can this credentials sign a transaction? - * (Only returns fail on a 'proxy' setup for airgapped operation) - * - * @return {undefined} - */ -API.prototype.canSign = function() { - return this.credentials && this.credentials.canSign(); -}; - - -API._extractPublicKeyRing = function(copayers) { - return _.map(copayers, function(copayer) { - var pkr = _.pick(copayer, ['xPubKey', 'requestPubKey']); - pkr.copayerName = copayer.name; - return pkr; - }); -}; - -/** - * sets up encryption for the extended private key - * - * @param {String} password Password used to encrypt - * @param {Object} opts optional: SJCL options to encrypt (.iter, .salt, etc). - * @return {undefined} - */ -API.prototype.setPrivateKeyEncryption = function(password, opts) { - this.credentials.setPrivateKeyEncryption(password, opts || API.privateKeyEncryptionOpts); -}; - -/** - * disables encryption for private key. - * wallet must be unlocked - * - */ -API.prototype.disablePrivateKeyEncryption = function(password, opts) { - return this.credentials.disablePrivateKeyEncryption(); -}; - -/** - * Locks private key (removes the unencrypted version and keep only the encrypted) - * - * @return {undefined} - */ -API.prototype.lock = function() { - this.credentials.lock(); -}; - - -/** - * Get current fee levels for the specified network - * - * @param {string} network - 'livenet' (default) or 'testnet' - * @param {Callback} cb - * @returns {Callback} cb - Returns error or an object with status information - */ -API.prototype.getFeeLevels = function(network, cb) { - var self = this; - - $.checkArgument(network || _.contains(['livenet', 'testnet'], network)); - - self._doGetRequest('/v1/feelevels/?network=' + (network || 'livenet'), function(err, result) { - if (err) return cb(err); - return cb(err, result); - }); -}; - -/** - * Get service version - * - * @param {Callback} cb - */ -API.prototype.getVersion = function(cb) { - this._doGetRequest('/v1/version/', cb); -}; - -API.prototype._checkKeyDerivation = function() { - var isInvalid = (this.keyDerivationOk === false); - if (isInvalid) { - log.error('Key derivation for this device is not working as expected'); - } - return !isInvalid; -}; - -/** - * - * Create a wallet. - * @param {String} walletName - * @param {String} copayerName - * @param {Number} m - * @param {Number} n - * @param {object} opts (optional: advanced options) - * @param {string} opts.network[='livenet'] - * @param {string} opts.singleAddress[=false] - The wallet will only ever have one address. - * @param {String} opts.walletPrivKey - set a walletPrivKey (instead of random) - * @param {String} opts.id - set a id for wallet (instead of server given) - * @param cb - * @return {undefined} - */ -API.prototype.createWallet = function(walletName, copayerName, m, n, opts, cb) { - var self = this; - - if (!self._checkKeyDerivation()) return cb(new Error('Cannot create new wallet')); - - if (opts) $.shouldBeObject(opts); - opts = opts || {}; - - var network = opts.network || 'livenet'; - if (!_.contains(['testnet', 'livenet'], network)) return cb(new Error('Invalid network')); - - if (!self.credentials) { - log.info('Generating new keys'); - self.seedFromRandom({ - network: network - }); - } else { - log.info('Using existing keys'); - } - - if (network != self.credentials.network) { - return cb(new Error('Existing keys were created for a different network')); - } - - var walletPrivKey = opts.walletPrivKey || new Bitcore.PrivateKey(); - - var c = self.credentials; - c.addWalletPrivateKey(walletPrivKey.toString()); - var encWalletName = Utils.encryptMessage(walletName, c.sharedEncryptingKey); - - var args = { - name: encWalletName, - m: m, - n: n, - pubKey: (new Bitcore.PrivateKey(walletPrivKey)).toPublicKey().toString(), - network: network, - singleAddress: !!opts.singleAddress, - id: opts.id, - }; - self._doPostRequest('/v2/wallets/', args, function(err, res) { - if (err) return cb(err); - - var walletId = res.walletId; - c.addWalletInfo(walletId, walletName, m, n, copayerName); - var secret = API._buildSecret(c.walletId, c.walletPrivKey, c.network); - - self._doJoinWallet(walletId, walletPrivKey, c.xPubKey, c.requestPubKey, copayerName, {}, - function(err, wallet) { - if (err) return cb(err); - return cb(null, n > 1 ? secret : null); - }); - }); -}; - -/** - * Join an existent wallet - * - * @param {String} secret - * @param {String} copayerName - * @param {Object} opts - * @param {Boolean} opts.dryRun[=false] - Simulate wallet join - * @param {Callback} cb - * @returns {Callback} cb - Returns the wallet - */ -API.prototype.joinWallet = function(secret, copayerName, opts, cb) { - var self = this; - - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: joinWallet should receive 4 parameters.'); - } - - if (!self._checkKeyDerivation()) return cb(new Error('Cannot join wallet')); - - opts = opts || {}; - - try { - var secretData = API.parseSecret(secret); - } catch (ex) { - return cb(ex); - } - - if (!self.credentials) { - self.seedFromRandom({ - network: secretData.network - }); - } - - self.credentials.addWalletPrivateKey(secretData.walletPrivKey.toString()); - self._doJoinWallet(secretData.walletId, secretData.walletPrivKey, self.credentials.xPubKey, self.credentials.requestPubKey, copayerName, { - dryRun: !!opts.dryRun, - }, function(err, wallet) { - if (err) return cb(err); - if (!opts.dryRun) { - self.credentials.addWalletInfo(wallet.id, wallet.name, wallet.m, wallet.n, copayerName); - } - return cb(null, wallet); - }); -}; - -/** - * Recreates a wallet, given credentials (with wallet id) - * - * @returns {Callback} cb - Returns the wallet - */ -API.prototype.recreateWallet = function(cb) { - $.checkState(this.credentials); - $.checkState(this.credentials.isComplete()); - $.checkState(this.credentials.walletPrivKey); - //$.checkState(this.credentials.hasWalletInfo()); - var self = this; - - // First: Try to get the wallet with current credentials - this.getStatus({ - includeExtendedInfo: true - }, function(err) { - // No error? -> Wallet is ready. - if (!err) { - log.info('Wallet is already created'); - return cb(); - }; - - var c = self.credentials; - var walletPrivKey = Bitcore.PrivateKey.fromString(c.walletPrivKey); - var walletId = c.walletId; - var supportBIP44AndP2PKH = c.derivationStrategy != Constants.DERIVATION_STRATEGIES.BIP45; - var encWalletName = Utils.encryptMessage(c.walletName || 'recovered wallet', c.sharedEncryptingKey); - - var args = { - name: encWalletName, - m: c.m, - n: c.n, - pubKey: walletPrivKey.toPublicKey().toString(), - network: c.network, - id: walletId, - supportBIP44AndP2PKH: supportBIP44AndP2PKH, - }; - - self._doPostRequest('/v2/wallets/', args, function(err, body) { - if (err) { - if (!(err instanceof Errors.WALLET_ALREADY_EXISTS)) - return cb(err); - - return self.addAccess({}, function(err) { - if (err) return cb(err); - self.openWallet(function(err) { - return cb(err); - }); - }); - } - - if (!walletId) { - walletId = body.walletId; - } - - var i = 1; - async.each(self.credentials.publicKeyRing, function(item, next) { - var name = item.copayerName || ('copayer ' + i++); - self._doJoinWallet(walletId, walletPrivKey, item.xPubKey, item.requestPubKey, name, { - supportBIP44AndP2PKH: supportBIP44AndP2PKH, - }, function(err) { - //Ignore error is copayer already in wallet - if (err && err instanceof Errors.COPAYER_IN_WALLET) return next(); - return next(err); - }); - }, cb); - }); - }); -}; - -API.prototype._processWallet = function(wallet) { - var self = this; - - var encryptingKey = self.credentials.sharedEncryptingKey; - - var name = Utils.decryptMessage(wallet.name, encryptingKey); - if (name != wallet.name) { - wallet.encryptedName = wallet.name; - } - wallet.name = name; - _.each(wallet.copayers, function(copayer) { - var name = Utils.decryptMessage(copayer.name, encryptingKey); - if (name != copayer.name) { - copayer.encryptedName = copayer.name; - } - copayer.name = name; - _.each(copayer.requestPubKeys, function(access) { - if (!access.name) return; - - var name = Utils.decryptMessage(access.name, encryptingKey); - if (name != access.name) { - access.encryptedName = access.name; - } - access.name = name; - }); - }); -}; - -API.prototype._processStatus = function(status) { - var self = this; - - function processCustomData(data) { - var copayers = data.wallet.copayers; - if (!copayers) return; - - var me = _.find(copayers, { - 'id': self.credentials.copayerId - }); - if (!me || !me.customData) return; - - var customData; - try { - customData = JSON.parse(Utils.decryptMessage(me.customData, self.credentials.personalEncryptingKey)); - } catch (e) { - log.warn('Could not decrypt customData:', me.customData); - } - if (!customData) return; - - // Add it to result - data.customData = customData; - - // Update walletPrivateKey - if (!self.credentials.walletPrivKey && customData.walletPrivKey) - self.credentials.addWalletPrivateKey(customData.walletPrivKey); - }; - - processCustomData(status); - self._processWallet(status.wallet); - self._processTxps(status.pendingTxps); -} - - -/** - * Get latest notifications - * - * @param {object} opts - * @param {String} lastNotificationId (optional) - The ID of the last received notification - * @param {String} timeSpan (optional) - A time window on which to look for notifications (in seconds) - * @returns {Callback} cb - Returns error or an array of notifications - */ -API.prototype.getNotifications = function(opts, cb) { - $.checkState(this.credentials); - - var self = this; - opts = opts || {}; - - var url = '/v1/notifications/'; - if (opts.lastNotificationId) { - url += '?notificationId=' + opts.lastNotificationId; - } else if (opts.timeSpan) { - url += '?timeSpan=' + opts.timeSpan; - } - - self._doGetRequest(url, function(err, result) { - if (err) return cb(err); - var notifications = _.filter(result, function(notification) { - return (notification.creatorId != self.credentials.copayerId); - }); - return cb(null, notifications); - }); -}; - -/** - * Get status of the wallet - * - * @param {Boolean} opts.twoStep[=false] - Optional: use 2-step balance computation for improved performance - * @param {Boolean} opts.includeExtendedInfo (optional: query extended status) - * @returns {Callback} cb - Returns error or an object with status information - */ -API.prototype.getStatus = function(opts, cb) { - $.checkState(this.credentials); - - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: getStatus should receive 2 parameters.') - } - - var self = this; - opts = opts || {}; - - var qs = []; - qs.push('includeExtendedInfo=' + (opts.includeExtendedInfo ? '1' : '0')); - qs.push('twoStep=' + (opts.twoStep ? '1' : '0')); - - self._doGetRequest('/v2/wallets/?' + qs.join('&'), function(err, result) { - if (err) return cb(err); - if (result.wallet.status == 'pending') { - var c = self.credentials; - result.wallet.secret = API._buildSecret(c.walletId, c.walletPrivKey, c.network); - } - - self._processStatus(result); - - return cb(err, result); - }); -}; - -/** - * Get copayer preferences - * - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.getPreferences = function(cb) { - $.checkState(this.credentials); - $.checkArgument(cb); - - var self = this; - self._doGetRequest('/v1/preferences/', function(err, preferences) { - if (err) return cb(err); - return cb(null, preferences); - }); -}; - -/** - * Save copayer preferences - * - * @param {Object} preferences - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.savePreferences = function(preferences, cb) { - $.checkState(this.credentials); - $.checkArgument(cb); - - var self = this; - self._doPutRequest('/v1/preferences/', preferences, cb); -}; - - -API.prototype._computeProposalSignature = function(args) { - var hash; - if (args.outputs) { - $.shouldBeArray(args.outputs); - // should match bws server createTx - var proposalHeader = { - outputs: _.map(args.outputs, function(output) { - $.shouldBeNumber(output.amount); - return _.pick(output, ['toAddress', 'amount', 'message']); - }), - message: args.message || null, - payProUrl: args.payProUrl || null, - }; - hash = Utils.getProposalHash(proposalHeader); - } else { - $.shouldBeNumber(args.amount); - hash = Utils.getProposalHash(args.toAddress, args.amount, args.message || null, args.payProUrl || null); - } - return Utils.signMessage(hash, this.credentials.requestPrivKey); -}; - -/** - * fetchPayPro - * - * @param opts.payProUrl URL for paypro request - * @returns {Callback} cb - Return error or the parsed payment protocol request - * Returns (err,paypro) - * paypro.amount - * paypro.toAddress - * paypro.memo - */ -API.prototype.fetchPayPro = function(opts, cb) { - $.checkArgument(opts) - .checkArgument(opts.payProUrl); - - PayPro.get({ - url: opts.payProUrl, - http: this.payProHttp, - }, function(err, paypro) { - if (err) - return cb(err); - - return cb(null, paypro); - }); -}; - -/** - * Gets list of utxos - * - * @param {Function} cb - * @param {Object} opts - * @param {Array} opts.addresses (optional) - List of addresses from where to fetch UTXOs. - * @returns {Callback} cb - Return error or the list of utxos - */ -API.prototype.getUtxos = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - opts = opts || {}; - var url = '/v1/utxos/'; - if (opts.addresses) { - url += '?' + querystring.stringify({ - addresses: [].concat(opts.addresses).join(',') - }); - } - this._doGetRequest(url, cb); -}; - -/** - * Send a transaction proposal - * - * @param {Object} opts - * @param {String} opts.toAddress | opts.outputs[].toAddress - * @param {Number} opts.amount | opts.outputs[].amount - * @param {String} opts.message | opts.outputs[].message - * @param {string} opts.feePerKb - Optional: Use an alternative fee per KB for this TX - * @param {String} opts.payProUrl - Optional: Tx is from a payment protocol URL - * @param {string} opts.excludeUnconfirmedUtxos - Optional: Do not use UTXOs of unconfirmed transactions as inputs - * @param {Object} opts.customData - Optional: Arbitrary data to store along with proposal - * @param {Array} opts.inputs - Optional: Inputs to be used in proposal. - * @param {Array} opts.outputs - Optional: Outputs to be used in proposal. - * @param {Array} opts.utxosToExclude - Optional: List of UTXOS (in form of txid:vout string) - * to exclude from coin selection for this proposal - * @returns {Callback} cb - Return error or the transaction proposal - */ -API.prototype.sendTxProposal = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(!opts.message || this.credentials.sharedEncryptingKey, 'Cannot create transaction with message without shared Encrypting key'); - $.checkArgument(opts); - - var self = this; - - var args = { - toAddress: opts.toAddress, - amount: opts.amount, - message: API._encryptMessage(opts.message, this.credentials.sharedEncryptingKey) || null, - feePerKb: opts.feePerKb, - payProUrl: opts.payProUrl || null, - excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos, - type: opts.type, - customData: opts.customData, - inputs: opts.inputs, - utxosToExclude: opts.utxosToExclude - }; - if (opts.outputs) { - args.outputs = _.map(opts.outputs, function(o) { - return { - toAddress: o.toAddress, - script: o.script, - amount: o.amount, - message: API._encryptMessage(o.message, self.credentials.sharedEncryptingKey) || null, - }; - }); - } - log.debug('Generating & signing tx proposal:', JSON.stringify(args)); - args.proposalSignature = this._computeProposalSignature(args); - - this._doPostRequest('/v1/txproposals/', args, function(err, txp) { - if (err) return cb(err); - return cb(null, txp); - }); -}; - -API.prototype._getCreateTxProposalArgs = function(opts) { - var self = this; - - var args = { - message: API._encryptMessage(opts.message, this.credentials.sharedEncryptingKey) || null, - fee: opts.fee, - feePerKb: opts.feePerKb, - changeAddress: opts.changeAddress, - payProUrl: opts.payProUrl || null, - excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos, - customData: opts.customData, - inputs: opts.inputs, - utxosToExclude: opts.utxosToExclude, - validateOutputs: opts.validateOutputs - }; - - args.outputs = _.map(opts.outputs, function(o) { - return { - toAddress: o.toAddress, - script: o.script, - amount: o.amount, - message: API._encryptMessage(o.message, self.credentials.sharedEncryptingKey) || null, - }; - }); - - return args; -}; - -/** - * Create a transaction proposal - * - * @param {Object} opts - * @param {Array} opts.outputs - List of outputs. - * @param {String} opts.outputs[].toAddress / opts.outputs[].script - * @param {Number} opts.outputs[].amount - * @param {String} opts.outputs[].message - * @param {string} opts.message - A message to attach to this transaction. - * @param {string} opts.fee - Optional: Use an alternative fee for this TX (mutually exclusive with feePerKb) - * @param {string} opts.feePerKb - Optional: Use an alternative fee per KB for this TX (mutually exclusive with fee) - * @param {string} opts.changeAddress - Optional. Use this address as the change address for the tx. The address should belong to the wallet. - * @param {String} opts.payProUrl - Optional: Tx is from a payment protocol URL - * @param {string} opts.excludeUnconfirmedUtxos - Optional: Do not use UTXOs of unconfirmed transactions as inputs - * @param {Object} opts.customData - Optional: Arbitrary data to store along with proposal - * @param {Array} opts.inputs - Optional: Inputs to be used in proposal. - * @param {Array} opts.outputs - Optional: Outputs to be used in proposal. - * @param {Array} opts.utxosToExclude - Optional: List of UTXOS (in form of txid:vout string) - * to exclude from coin selection for this proposal - * @returns {Callback} cb - Return error or the transaction proposal - */ -API.prototype.createTxProposal = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(!opts.message || this.credentials.sharedEncryptingKey, 'Cannot create transaction with message without shared Encrypting key'); - $.checkArgument(opts); - $.checkState(!_.isNumber(opts.fee) || !_.isNumber(opts.feePerKb)); - - var self = this; - - var args = self._getCreateTxProposalArgs(opts); - - self._doPostRequest('/v2/txproposals/', args, function(err, txp) { - if (err) return cb(err); - - if (!Verifier.checkProposalCreation(args, txp)) { - return cb(new Errors.SERVER_COMPROMISED); - } - - self._processTxps(txp); - return cb(null, txp); - }); -}; - -/** - * Publish a transaction proposal - * - * @param {Object} opts - * @param {Object} opts.txp - The transaction proposal object returned by the API#createTxProposal method - * @returns {Callback} cb - Return error or null - */ -API.prototype.publishTxProposal = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(opts) - .checkArgument(opts.txp); - - $.checkState(parseInt(opts.txp.version) >= 3); - - var self = this; - - var t = Utils.buildTx(opts.txp); - var hash = t.uncheckedSerialize(); - var args = { - proposalSignature: Utils.signMessage(hash, self.credentials.requestPrivKey) - }; - - var url = '/v1/txproposals/' + opts.txp.id + '/publish/'; - self._doPostRequest(url, args, function(err, txp) { - if (err) return cb(err); - return cb(null, txp); - }); -}; - -/** - * Create a new address - * - * @param {Object} opts - * @param {Boolean} opts.ignoreMaxGap[=false] - * @param {Callback} cb - * @returns {Callback} cb - Return error or the address - */ -API.prototype.createAddress = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: createAddress should receive 2 parameters.') - } - - if (!self._checkKeyDerivation()) return cb(new Error('Cannot create new address for this wallet')); - - opts = opts || {}; - - self._doPostRequest('/v3/addresses/', opts, function(err, address) { - if (err) return cb(err); - - if (!Verifier.checkAddress(self.credentials, address)) { - return cb(new Errors.SERVER_COMPROMISED); - } - - return cb(null, address); - }); -}; - -/** - * Get your main addresses - * - * @param {Object} opts - * @param {Boolean} opts.doNotVerify - * @param {Numeric} opts.limit (optional) - Limit the resultset. Return all addresses by default. - * @param {Boolean} [opts.reverse=false] (optional) - Reverse the order of returned addresses. - * @param {Callback} cb - * @returns {Callback} cb - Return error or the array of addresses - */ -API.prototype.getMainAddresses = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - - opts = opts || {}; - - var args = []; - if (opts.limit) args.push('limit=' + opts.limit); - if (opts.reverse) args.push('reverse=1'); - var qs = ''; - if (args.length > 0) { - qs = '?' + args.join('&'); - } - var url = '/v1/addresses/' + qs; - - self._doGetRequest(url, function(err, addresses) { - if (err) return cb(err); - - if (!opts.doNotVerify) { - var fake = _.any(addresses, function(address) { - return !Verifier.checkAddress(self.credentials, address); - }); - if (fake) - return cb(new Errors.SERVER_COMPROMISED); - } - return cb(null, addresses); - }); -}; - -/** - * Update wallet balance - * - * @param {Boolean} opts.twoStep[=false] - Optional: use 2-step balance computation for improved performance - * @param {Callback} cb - */ -API.prototype.getBalance = function(opts, cb) { - if (!cb) { - cb = opts; - opts = {}; - log.warn('DEPRECATED WARN: getBalance should receive 2 parameters.') - } - - var self = this; - opts = opts || {}; - - $.checkState(this.credentials && this.credentials.isComplete()); - var url = '/v1/balance/'; - if (opts.twoStep) url += '?twoStep=1'; - this._doGetRequest(url, cb); -}; - -/** - * Get list of transactions proposals - * - * @param {Object} opts - * @param {Boolean} opts.doNotVerify - * @param {Boolean} opts.forAirGapped - * @param {Boolean} opts.doNotEncryptPkr - * @return {Callback} cb - Return error or array of transactions proposals - */ -API.prototype.getTxProposals = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - - self._doGetRequest('/v1/txproposals/', function(err, txps) { - if (err) return cb(err); - - self._processTxps(txps); - async.every(txps, - function(txp, acb) { - if (opts.doNotVerify) return acb(true); - self.getPayPro(txp, function(err, paypro) { - - var isLegit = Verifier.checkTxProposal(self.credentials, txp, { - paypro: paypro, - }); - - return acb(isLegit); - }); - }, - function(isLegit) { - if (!isLegit) - return cb(new Errors.SERVER_COMPROMISED); - - var result; - if (opts.forAirGapped) { - result = { - txps: JSON.parse(JSON.stringify(txps)), - encryptedPkr: opts.doNotEncryptPkr ? null : Utils.encryptMessage(JSON.stringify(self.credentials.publicKeyRing), self.credentials.personalEncryptingKey), - unencryptedPkr: opts.doNotEncryptPkr ? JSON.stringify(self.credentials.publicKeyRing) : null, - m: self.credentials.m, - n: self.credentials.n, - }; - } else { - result = txps; - } - return cb(null, result); - }); - }); -}; - -API.prototype.getPayPro = function(txp, cb) { - var self = this; - if (!txp.payProUrl || this.doNotVerifyPayPro) - return cb(); - - PayPro.get({ - url: txp.payProUrl, - http: self.payProHttp, - }, function(err, paypro) { - if (err) return cb(new Error('Cannot check transaction now:' + err)); - return cb(null, paypro); - }); -}; - - -/** - * Sign a transaction proposal - * - * @param {Object} txp - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.signTxProposal = function(txp, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(txp.creatorId); - - var self = this; - - if (!txp.signatures) { - if (!self.canSign()) - return cb(new Error('You do not have the required keys to sign transactions')); - - if (self.isPrivKeyEncrypted()) - return cb(new Error('Private Key is encrypted, cannot sign')); - } - - self.getPayPro(txp, function(err, paypro) { - if (err) return cb(err); - - var isLegit = Verifier.checkTxProposal(self.credentials, txp, { - paypro: paypro, - }); - - if (!isLegit) - return cb(new Errors.SERVER_COMPROMISED); - - var signatures = txp.signatures; - - if (_.isEmpty(signatures)) { - try { - signatures = self._signTxp(txp); - } catch (ex) { - log.error('Error signing tx', ex); - return cb(ex); - } - } - - var url = '/v1/txproposals/' + txp.id + '/signatures/'; - var args = { - signatures: signatures - }; - - self._doPostRequest(url, args, function(err, txp) { - if (err) return cb(err); - self._processTxps(txp); - return cb(null, txp); - }); - }); -}; - -/** - * Sign transaction proposal from AirGapped - * - * @param {Object} txp - * @param {String} encryptedPkr - * @param {Number} m - * @param {Number} n - * @return {Object} txp - Return transaction - */ -API.prototype.signTxProposalFromAirGapped = function(txp, encryptedPkr, m, n) { - $.checkState(this.credentials); - - var self = this; - - if (!self.canSign()) - throw new Errors.MISSING_PRIVATE_KEY; - - if (self.isPrivKeyEncrypted()) - throw new Errors.ENCRYPTED_PRIVATE_KEY; - - var publicKeyRing; - try { - publicKeyRing = JSON.parse(Utils.decryptMessage(encryptedPkr, self.credentials.personalEncryptingKey)); - } catch (ex) { - throw new Error('Could not decrypt public key ring'); - } - - if (!_.isArray(publicKeyRing) || publicKeyRing.length != n) { - throw new Error('Invalid public key ring'); - } - - self.credentials.m = m; - self.credentials.n = n; - self.credentials.addressType = txp.addressType; - self.credentials.addPublicKeyRing(publicKeyRing); - - if (!Verifier.checkTxProposalSignature(self.credentials, txp)) - throw new Error('Fake transaction proposal'); - - return self._signTxp(txp); -}; - - -/** - * Sign transaction proposal from AirGapped - * - * @param {String} key - A mnemonic phrase or an xprv HD private key - * @param {Object} txp - * @param {String} unencryptedPkr - * @param {Number} m - * @param {Number} n - * @param {Object} opts - * @param {String} opts.passphrase - * @param {Number} opts.account - default 0 - * @param {String} opts.derivationStrategy - default 'BIP44' - * @return {Object} txp - Return transaction - */ -API.signTxProposalFromAirGapped = function(key, txp, unencryptedPkr, m, n, opts) { - var self = this; - opts = opts || {} - - var publicKeyRing = JSON.parse(unencryptedPkr); - - if (!_.isArray(publicKeyRing) || publicKeyRing.length != n) { - throw new Error('Invalid public key ring'); - } - - var newClient = new API({ - baseUrl: 'https://bws.example.com/bws/api', - verbose: false, - }) - - if (key.slice(0, 4) === 'xprv' || key.slice(0, 4) === 'tprv') { - if (key.slice(0, 4) === 'xprv' && txp.network == 'testnet') throw new Error("testnet HD keys must start with tprv"); - if (key.slice(0, 4) === 'tprv' && txp.network == 'livenet') throw new Error("livenet HD keys must start with xprv"); - newClient.seedFromExtendedPrivateKey(key, { - 'account': opts.account, - 'derivationStrategy': opts.derivationStrategy - }); - } else { - newClient.seedFromMnemonic(key, { - 'network': txp.network, - 'passphrase': opts.passphrase, - 'account': opts.account, - 'derivationStrategy': opts.derivationStrategy - }) - } - - newClient.credentials.m = m; - newClient.credentials.n = n; - newClient.credentials.addressType = txp.addressType; - newClient.credentials.addPublicKeyRing(publicKeyRing); - - if (!Verifier.checkTxProposalSignature(newClient.credentials, txp)) - throw new Error('Fake transaction proposal'); - - return newClient._signTxp(txp); -}; - - -/** - * Reject a transaction proposal - * - * @param {Object} txp - * @param {String} reason - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.rejectTxProposal = function(txp, reason, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - $.checkArgument(cb); - - var self = this; - - var url = '/v1/txproposals/' + txp.id + '/rejections/'; - var args = { - reason: API._encryptMessage(reason, self.credentials.sharedEncryptingKey) || '', - }; - self._doPostRequest(url, args, function(err, txp) { - if (err) return cb(err); - self._processTxps(txp); - return cb(null, txp); - }); -}; - -/** - * Broadcast raw transaction - * - * @param {Object} opts - * @param {String} opts.network - * @param {String} opts.rawTx - * @param {Callback} cb - * @return {Callback} cb - Return error or txid - */ -API.prototype.broadcastRawTx = function(opts, cb) { - $.checkState(this.credentials); - $.checkArgument(cb); - - var self = this; - - opts = opts || {}; - - var url = '/v1/broadcast_raw/'; - self._doPostRequest(url, opts, function(err, txid) { - if (err) return cb(err); - return cb(null, txid); - }); -}; - -API.prototype._doBroadcast = function(txp, cb) { - var self = this; - var url = '/v1/txproposals/' + txp.id + '/broadcast/'; - self._doPostRequest(url, {}, function(err, txp) { - if (err) return cb(err); - return cb(null, txp); - }); -}; - - -/** - * Broadcast a transaction proposal - * - * @param {Object} txp - * @param {Callback} cb - * @return {Callback} cb - Return error or object - */ -API.prototype.broadcastTxProposal = function(txp, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - - self.getPayPro(txp, function(err, paypro) { - - if (paypro) { - - var t = Utils.buildTx(txp); - self._applyAllSignatures(txp, t); - - PayPro.send({ - http: self.payProHttp, - url: txp.payProUrl, - amountSat: txp.amount, - refundAddr: txp.changeAddress.address, - merchant_data: paypro.merchant_data, - rawTx: t.serialize({ - disableSmallFees: true, - disableLargeFees: true, - disableDustOutputs: true - }), - }, function(err, ack, memo) { - if (err) return cb(err); - self._doBroadcast(txp, function(err, txp) { - return cb(err, txp, memo); - }); - }); - } else { - self._doBroadcast(txp, cb); - } - }); -}; - -/** - * Remove a transaction proposal - * - * @param {Object} txp - * @param {Callback} cb - * @return {Callback} cb - Return error or empty - */ -API.prototype.removeTxProposal = function(txp, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - - var url = '/v1/txproposals/' + txp.id; - self._doDeleteRequest(url, function(err) { - return cb(err); - }); -}; - -/** - * Get transaction history - * - * @param {Object} opts - * @param {Number} opts.skip (defaults to 0) - * @param {Number} opts.limit - * @param {Boolean} opts.includeExtendedInfo - * @param {Callback} cb - * @return {Callback} cb - Return error or array of transactions - */ -API.prototype.getTxHistory = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - var args = []; - if (opts) { - if (opts.skip) args.push('skip=' + opts.skip); - if (opts.limit) args.push('limit=' + opts.limit); - if (opts.includeExtendedInfo) args.push('includeExtendedInfo=1'); - } - var qs = ''; - if (args.length > 0) { - qs = '?' + args.join('&'); - } - - var url = '/v1/txhistory/' + qs; - self._doGetRequest(url, function(err, txs) { - if (err) return cb(err); - self._processTxps(txs); - return cb(null, txs); - }); -}; - -/** - * getTx - * - * @param {String} TransactionId - * @return {Callback} cb - Return error or transaction - */ -API.prototype.getTx = function(id, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - var url = '/v1/txproposals/' + id; - this._doGetRequest(url, function(err, txp) { - if (err) return cb(err); - - self._processTxps(txp); - return cb(null, txp); - }); -}; - - -/** - * Start an address scanning process. - * When finished, the scanning process will send a notification 'ScanFinished' to all copayers. - * - * @param {Object} opts - * @param {Boolean} opts.includeCopayerBranches (defaults to false) - * @param {Callback} cb - */ -API.prototype.startScan = function(opts, cb) { - $.checkState(this.credentials && this.credentials.isComplete()); - - var self = this; - - var args = { - includeCopayerBranches: opts.includeCopayerBranches, - }; - - self._doPostRequest('/v1/addresses/scan', args, function(err) { - return cb(err); - }); -}; - -/** - * Adds access to the current copayer - * @param {Object} opts - * @param {bool} opts.generateNewKey Optional: generate a new key for the new access - * @param {string} opts.restrictions - * - cannotProposeTXs - * - cannotXXX TODO - * @param {string} opts.name (name for the new access) - * - * return the accesses Wallet and the requestPrivateKey - */ -API.prototype.addAccess = function(opts, cb) { - $.checkState(this.credentials && this.credentials.canSign()); - - opts = opts || {}; - - var reqPrivKey = new Bitcore.PrivateKey(opts.generateNewKey ? null : this.credentials.requestPrivKey); - var requestPubKey = reqPrivKey.toPublicKey().toString(); - - var xPriv = new Bitcore.HDPrivateKey(this.credentials.xPrivKey) - .derive(this.credentials.getBaseAddressDerivationPath()); - var sig = Utils.signRequestPubKey(requestPubKey, xPriv); - var copayerId = this.credentials.copayerId; - - var encCopayerName = opts.name ? Utils.encryptMessage(opts.name, this.credentials.sharedEncryptingKey) : null; - - var opts = { - copayerId: copayerId, - requestPubKey: requestPubKey, - signature: sig, - name: encCopayerName, - restrictions: opts.restrictions, - }; - - this._doPutRequest('/v1/copayers/' + copayerId + '/', opts, function(err, res) { - if (err) return cb(err); - return cb(null, res.wallet, reqPrivKey); - }); -}; - -/** - * Get a note associated with the specified txid - * @param {Object} opts - * @param {string} opts.txid - The txid to associate this note with - */ -API.prototype.getTxNote = function(opts, cb) { - $.checkState(this.credentials); - - var self = this; - - opts = opts || {}; - self._doGetRequest('/v1/txnotes/' + opts.txid + '/', function(err, note) { - if (err) return cb(err); - self._processTxNotes(note); - return cb(null, note); - }); -}; - -/** - * Edit a note associated with the specified txid - * @param {Object} opts - * @param {string} opts.txid - The txid to associate this note with - * @param {string} opts.body - The contents of the note - */ -API.prototype.editTxNote = function(opts, cb) { - $.checkState(this.credentials); - - opts = opts || {}; - if (opts.body) { - opts.body = API._encryptMessage(opts.body, this.credentials.sharedEncryptingKey); - } - this._doPutRequest('/v1/txnotes/' + opts.txid + '/', opts, function(err, res) { - return cb(err); - }); -}; - -/** - * Get all notes edited after the specified date - * @param {Object} opts - * @param {string} opts.minTs - The starting timestamp - */ -API.prototype.getTxNotes = function(opts, cb) { - $.checkState(this.credentials); - - var self = this; - - opts = opts || {}; - var args = []; - if (_.isNumber(opts.minTs)) { - args.push('minTs=' + opts.minTs); - } - var qs = ''; - if (args.length > 0) { - qs = '?' + args.join('&'); - } - - self._doGetRequest('/v1/txnotes/' + qs, function(err, notes) { - if (err) return cb(err); - self._processTxNotes(notes); - return cb(null, notes); - }); -}; - -/** - * Returns exchange rate for the specified currency & timestamp. - * @param {Object} opts - * @param {string} opts.code - Currency ISO code. - * @param {Date} [opts.ts] - A timestamp to base the rate on (default Date.now()). - * @param {String} [opts.provider] - A provider of exchange rates (default 'BitPay'). - * @returns {Object} rates - The exchange rate. - */ -API.prototype.getFiatRate = function(opts, cb) { - $.checkState(this.credentials); - $.checkArgument(cb); - - var self = this; - - var opts = opts || {}; - - var args = []; - if (opts.ts) args.push('ts=' + opts.ts); - if (opts.provider) args.push('provider=' + opts.provider); - var qs = ''; - if (args.length > 0) { - qs = '?' + args.join('&'); - } - - self._doGetRequest('/v1/fiatrates/' + opts.code + '/' + qs, function(err, rates) { - if (err) return cb(err); - return cb(null, rates); - }); -} - -/** - * Returns subscription status. - * @param {Object} opts - * @param {String} opts.type - Device type (ios or android). - * @param {String} opts.token - Device token. - * @returns {Object} response - Status of subscription. - */ -API.prototype.pushNotificationsSubscribe = function(opts, cb) { - var url = '/v1/pushnotifications/subscriptions/'; - this._doPostRequest(url, opts, function(err, response) { - if (err) return cb(err); - return cb(null, response); - }); -}; - -/** - * Returns unsubscription status. - * @param {String} token - Device token - * @return {Callback} cb - Return error if exists - */ -API.prototype.pushNotificationsUnsubscribe = function(cb) { - var url = '/v1/pushnotifications/subscriptions/'; - this._doDeleteRequest(url, function(err) { - if (err) return cb(err); - return cb(null); - }); -}; - -/** - * Returns send max information. - * @param {String} opts - * @param {Number} opts.feePerKb - Fee value - * @param {Boolean} opts.excludeUnconfirmedUtxos - Indicates it if should use (or not) the unconfirmed utxos - * @param {Boolean} opts.returnInputs - Indicates it if should return (or not) the inputs - * @return {Callback} cb - Return error (if exists) and object result - */ -API.prototype.getSendMaxInfo = function(opts, cb) { - var self = this; - var args = []; - opts = opts || {}; - - if (opts.feePerKb) args.push('feePerKb=' + opts.feePerKb); - if (opts.excludeUnconfirmedUtxos) args.push('excludeUnconfirmedUtxos=1'); - if (opts.returnInputs) args.push('returnInputs=1'); - - var qs = ''; - - if (args.length > 0) - qs = '?' + args.join('&'); - - var url = '/v1/sendmaxinfo/' + qs; - - self._doGetRequest(url, function(err, result) { - if (err) return cb(err); - return cb(null, result); - }); -}; - - -/* - * - * Compatibility Functions - * - */ - -API.prototype._oldCopayDecrypt = function(username, password, blob) { - var SEP1 = '@#$'; - var SEP2 = '%^#@'; - - var decrypted; - try { - var passphrase = username + SEP1 + password; - decrypted = sjcl.decrypt(passphrase, blob); - } catch (e) { - passphrase = username + SEP2 + password; - try { - decrypted = sjcl.decrypt(passphrase, blob); - } catch (e) { - log.debug(e); - }; - } - - if (!decrypted) - return null; - - var ret; - try { - ret = JSON.parse(decrypted); - } catch (e) {}; - return ret; -}; - - -API.prototype.getWalletIdsFromOldCopay = function(username, password, blob) { - var p = this._oldCopayDecrypt(username, password, blob); - if (!p) return null; - var ids = p.walletIds.concat(_.keys(p.focusedTimestamps)); - return _.uniq(ids); -}; - - -/** - * createWalletFromOldCopay - * - * @param username - * @param password - * @param blob - * @param cb - * @return {undefined} - */ -API.prototype.createWalletFromOldCopay = function(username, password, blob, cb) { - var self = this; - var w = this._oldCopayDecrypt(username, password, blob); - if (!w) return cb(new Error('Could not decrypt')); - - if (w.publicKeyRing.copayersExtPubKeys.length != w.opts.totalCopayers) - return cb(new Error('Wallet is incomplete, cannot be imported')); - - this.credentials = Credentials.fromOldCopayWallet(w); - this.recreateWallet(cb); -}; - -module.exports = API; - -}).call(this,require('_process'),require("buffer").Buffer) -},{"../package.json":314,"./common":5,"./credentials":7,"./errors":8,"./log":11,"./paypro":12,"./verifier":13,"_process":533,"async":14,"bip38":15,"bitcore-lib":64,"bitcore-mnemonic":136,"browser-request":174,"buffer":332,"events":528,"json-stable-stringify":175,"lodash":179,"preconditions":180,"querystring":537,"request":185,"sjcl":313,"url":564,"util":566}],3:[function(require,module,exports){ -'use strict'; - -var Constants = {}; - -Constants.SCRIPT_TYPES = { - P2SH: 'P2SH', - P2PKH: 'P2PKH', -}; -Constants.DERIVATION_STRATEGIES = { - BIP44: 'BIP44', - BIP45: 'BIP45', - BIP48: 'BIP48', -}; - -Constants.PATHS = { - REQUEST_KEY: "m/1'/0", - TXPROPOSAL_KEY: "m/1'/1", - REQUEST_KEY_AUTH: "m/2", // relative to BASE -}; - -Constants.BIP45_SHARED_INDEX = 0x80000000 - 1; - -Constants.UNITS = { - btc: { - toSatoshis: 100000000, - full: { - maxDecimals: 8, - minDecimals: 8, - }, - short: { - maxDecimals: 6, - minDecimals: 2, - } - }, - bit: { - toSatoshis: 100, - full: { - maxDecimals: 2, - minDecimals: 2, - }, - short: { - maxDecimals: 0, - minDecimals: 0, - } - }, -}; - -module.exports = Constants; - -},{}],4:[function(require,module,exports){ -'use strict'; - -var Defaults = {}; - -Defaults.DEFAULT_FEE_PER_KB = 10000; -Defaults.MIN_FEE_PER_KB = 0; -Defaults.MAX_FEE_PER_KB = 1000000; -Defaults.MAX_TX_FEE = 1 * 1e8; - -module.exports = Defaults; - -},{}],5:[function(require,module,exports){ -var Common = {}; - -Common.Constants = require('./constants'); -Common.Defaults = require('./defaults'); -Common.Utils = require('./utils'); - -module.exports = Common; - -},{"./constants":3,"./defaults":4,"./utils":6}],6:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var _ = require('lodash'); -var $ = require('preconditions').singleton(); -var sjcl = require('sjcl'); -var Stringify = require('json-stable-stringify'); - -var Bitcore = require('bitcore-lib'); -var Address = Bitcore.Address; -var PrivateKey = Bitcore.PrivateKey; -var PublicKey = Bitcore.PublicKey; -var crypto = Bitcore.crypto; -var encoding = Bitcore.encoding; - -var Constants = require('./constants'); -var Defaults = require('./defaults'); - -function Utils() {}; - -Utils.SJCL = {}; - -Utils.encryptMessage = function(message, encryptingKey) { - var key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.encrypt(key, message, _.defaults({ - ks: 128, - iter: 1, - }, Utils.SJCL)); -}; - -Utils.decryptMessage = function(cyphertextJson, encryptingKey) { - try { - var key = sjcl.codec.base64.toBits(encryptingKey); - return sjcl.decrypt(key, cyphertextJson); - } catch (ex) { - return cyphertextJson; - } -}; - -/* TODO: It would be nice to be compatible with bitcoind signmessage. How - * the hash is calculated there? */ -Utils.hashMessage = function(text) { - $.checkArgument(text); - var buf = new Buffer(text); - var ret = crypto.Hash.sha256sha256(buf); - ret = new Bitcore.encoding.BufferReader(ret).readReverse(); - return ret; -}; - - -Utils.signMessage = function(text, privKey) { - $.checkArgument(text); - var priv = new PrivateKey(privKey); - var hash = Utils.hashMessage(text); - return crypto.ECDSA.sign(hash, priv, 'little').toString(); -}; - - -Utils.verifyMessage = function(text, signature, pubKey) { - $.checkArgument(text); - $.checkArgument(pubKey); - - if (!signature) - return false; - - var pub = new PublicKey(pubKey); - var hash = Utils.hashMessage(text); - - try { - var sig = new crypto.Signature.fromString(signature); - return crypto.ECDSA.verify(hash, sig, pub, 'little'); - } catch (e) { - return false; - } -}; - -Utils.privateKeyToAESKey = function(privKey) { - $.checkArgument(privKey && _.isString(privKey)); - $.checkArgument(Bitcore.PrivateKey.isValid(privKey), 'The private key received is invalid'); - var pk = Bitcore.PrivateKey.fromString(privKey); - return Bitcore.crypto.Hash.sha256(pk.toBuffer()).slice(0, 16).toString('base64'); -}; - -Utils.getCopayerHash = function(name, xPubKey, requestPubKey) { - return [name, xPubKey, requestPubKey].join('|'); -}; - -Utils.getProposalHash = function(proposalHeader) { - function getOldHash(toAddress, amount, message, payProUrl) { - return [toAddress, amount, (message || ''), (payProUrl || '')].join('|'); - }; - - // For backwards compatibility - if (arguments.length > 1) { - return getOldHash.apply(this, arguments); - } - - return Stringify(proposalHeader); -}; - -Utils.deriveAddress = function(scriptType, publicKeyRing, path, m, network) { - $.checkArgument(_.contains(_.values(Constants.SCRIPT_TYPES), scriptType)); - - var publicKeys = _.map(publicKeyRing, function(item) { - var xpub = new Bitcore.HDPublicKey(item.xPubKey); - return xpub.derive(path).publicKey; - }); - - var bitcoreAddress; - switch (scriptType) { - case Constants.SCRIPT_TYPES.P2SH: - bitcoreAddress = Address.createMultisig(publicKeys, m, network); - break; - case Constants.SCRIPT_TYPES.P2PKH: - $.checkState(_.isArray(publicKeys) && publicKeys.length == 1); - bitcoreAddress = Address.fromPublicKey(publicKeys[0], network); - break; - } - - return { - address: bitcoreAddress.toString(), - path: path, - publicKeys: _.invoke(publicKeys, 'toString'), - }; -}; - -Utils.xPubToCopayerId = function(xpub) { - var hash = sjcl.hash.sha256.hash(xpub); - return sjcl.codec.hex.fromBits(hash); -}; - -Utils.signRequestPubKey = function(requestPubKey, xPrivKey) { - var priv = new Bitcore.HDPrivateKey(xPrivKey).derive(Constants.PATHS.REQUEST_KEY_AUTH).privateKey; - return Utils.signMessage(requestPubKey, priv); -}; - -Utils.verifyRequestPubKey = function(requestPubKey, signature, xPubKey) { - var pub = (new Bitcore.HDPublicKey(xPubKey)).derive(Constants.PATHS.REQUEST_KEY_AUTH).publicKey; - return Utils.verifyMessage(requestPubKey, signature, pub.toString()); -}; - -Utils.formatAmount = function(satoshis, unit, opts) { - $.shouldBeNumber(satoshis); - $.checkArgument(_.contains(_.keys(Constants.UNITS), unit)); - - function roundDown(number, decimals) { - var exp = Math.pow(10, decimals || 0); - return (Math.floor(number * exp) / exp); - } - - function addSeparators(nStr, thousands, decimal, minDecimals) { - nStr = nStr.replace('.', decimal); - var x = nStr.split(decimal); - var x0 = x[0]; - var x1 = x[1]; - - x1 = _.dropRightWhile(x1, function(n, i) { - return n == '0' && i >= minDecimals; - }).join(''); - var x2 = x.length > 1 ? decimal + x1 : ''; - - x0 = x0.replace(/\B(?=(\d{3})+(?!\d))/g, thousands); - return x0 + x2; - } - - opts = opts || {}; - - var u = Constants.UNITS[unit]; - var precision = opts.fullPrecision ? 'full' : 'short'; - - var amount = roundDown((satoshis / u.toSatoshis), u[precision].maxDecimals).toFixed(u[precision].maxDecimals); - return addSeparators(amount, opts.thousandsSeparator || ',', opts.decimalSeparator || '.', u[precision].minDecimals); -}; - -Utils.buildTx = function(txp) { - var t = new Bitcore.Transaction(); - - $.checkState(_.contains(_.values(Constants.SCRIPT_TYPES), txp.addressType)); - - switch (txp.addressType) { - case Constants.SCRIPT_TYPES.P2SH: - _.each(txp.inputs, function(i) { - t.from(i, i.publicKeys, txp.requiredSignatures); - }); - break; - case Constants.SCRIPT_TYPES.P2PKH: - t.from(txp.inputs); - break; - } - - if (txp.toAddress && txp.amount && !txp.outputs) { - t.to(txp.toAddress, txp.amount); - } else if (txp.outputs) { - _.each(txp.outputs, function(o) { - $.checkState(o.script || o.toAddress, 'Output should have either toAddress or script specified'); - if (o.script) { - t.addOutput(new Bitcore.Transaction.Output({ - script: o.script, - satoshis: o.amount - })); - } else { - t.to(o.toAddress, o.amount); - } - }); - } - - if (_.startsWith(txp.version, '1.')) { - Bitcore.Transaction.FEE_SECURITY_MARGIN = 1; - t.feePerKb(txp.feePerKb); - } else { - t.fee(txp.fee); - } - - t.change(txp.changeAddress.address); - - // Shuffle outputs for improved privacy - if (t.outputs.length > 1) { - var outputOrder = _.reject(txp.outputOrder, function(order) { - return order >= t.outputs.length; - }); - $.checkState(t.outputs.length == outputOrder.length); - t.sortOutputs(function(outputs) { - return _.map(outputOrder, function(i) { - return outputs[i]; - }); - }); - } - - // Validate inputs vs outputs independently of Bitcore - var totalInputs = _.reduce(txp.inputs, function(memo, i) { - return +i.satoshis + memo; - }, 0); - var totalOutputs = _.reduce(t.outputs, function(memo, o) { - return +o.satoshis + memo; - }, 0); - - $.checkState(totalInputs - totalOutputs >= 0); - $.checkState(totalInputs - totalOutputs <= Defaults.MAX_TX_FEE); - - return t; -}; - - -module.exports = Utils; - -}).call(this,require("buffer").Buffer) -},{"./constants":3,"./defaults":4,"bitcore-lib":64,"buffer":332,"json-stable-stringify":175,"lodash":179,"preconditions":180,"sjcl":313}],7:[function(require,module,exports){ -(function (Buffer){ -'use strict'; - -var $ = require('preconditions').singleton(); -var _ = require('lodash'); - -var Bitcore = require('bitcore-lib'); -var Mnemonic = require('bitcore-mnemonic'); -var sjcl = require('sjcl'); - -var Common = require('./common'); -var Constants = Common.Constants; -var Utils = Common.Utils; - -var FIELDS = [ - 'network', - 'xPrivKey', - 'xPrivKeyEncrypted', - 'xPubKey', - 'requestPrivKey', - 'requestPubKey', - 'copayerId', - 'publicKeyRing', - 'walletId', - 'walletName', - 'm', - 'n', - 'walletPrivKey', - 'personalEncryptingKey', - 'sharedEncryptingKey', - 'copayerName', - 'externalSource', - 'mnemonic', - 'mnemonicEncrypted', - 'entropySource', - 'mnemonicHasPassphrase', - 'derivationStrategy', - 'account', - 'addressType', -]; - -function Credentials() { - this.version = '1.0.0'; - this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP44; - this.account = 0; -}; - -function _checkNetwork(network) { - if (!_.contains(['livenet', 'testnet'], network)) throw new Error('Invalid network'); -}; - -Credentials.create = function(network) { - _checkNetwork(network); - - var x = new Credentials(); - - x.network = network; - x.xPrivKey = (new Bitcore.HDPrivateKey(network)).toString(); - x._expand(); - return x; -}; - -var wordsForLang = { - 'en': Mnemonic.Words.ENGLISH, - 'es': Mnemonic.Words.SPANISH, - 'ja': Mnemonic.Words.JAPANESE, - 'zh': Mnemonic.Words.CHINESE, - 'fr': Mnemonic.Words.FRENCH, - 'it': Mnemonic.Words.ITALIAN, -}; - -Credentials.createWithMnemonic = function(network, passphrase, language, account, opts) { - _checkNetwork(network); - if (!wordsForLang[language]) throw new Error('Unsupported language'); - $.shouldBeNumber(account); - - opts = opts || {}; - - var m = new Mnemonic(wordsForLang[language]); - while (!Mnemonic.isValid(m.toString())) { - m = new Mnemonic(wordsForLang[language]) - }; - var x = new Credentials(); - - x.network = network; - x.account = account; - x.xPrivKey = m.toHDPrivateKey(passphrase, network).toString(); - x._expand(); - x.mnemonic = m.phrase; - x.mnemonicHasPassphrase = !!passphrase; - - return x; -}; - -Credentials.fromExtendedPrivateKey = function(xPrivKey, account, derivationStrategy, opts) { - $.shouldBeNumber(account); - $.checkArgument(_.contains(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); - - opts = opts || {}; - - var x = new Credentials(); - x.xPrivKey = xPrivKey; - x.account = account; - x.derivationStrategy = derivationStrategy; - x._expand(); - return x; -}; - -// note that mnemonic / passphrase is NOT stored -Credentials.fromMnemonic = function(network, words, passphrase, account, derivationStrategy, opts) { - _checkNetwork(network); - $.shouldBeNumber(account); - $.checkArgument(_.contains(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); - - opts = opts || {}; - - var m = new Mnemonic(words); - var x = new Credentials(); - x.xPrivKey = m.toHDPrivateKey(passphrase, network).toString(); - x.mnemonic = words; - x.mnemonicHasPassphrase = !!passphrase; - x.account = account; - x.derivationStrategy = derivationStrategy; - x._expand(); - return x; -}; - -/* - * BWC uses - * xPrivKey -> m/44'/network'/account' -> Base Address Key - * so, xPubKey is PublicKeyHD(xPrivKey.derive("m/44'/network'/account'"). - * - * For external sources, this derivation should be done before - * call fromExtendedPublicKey - * - * entropySource should be a HEX string containing pseudo-random data, that can - * be deterministically derived from the xPrivKey, and should not be derived from xPubKey - */ -Credentials.fromExtendedPublicKey = function(xPubKey, source, entropySourceHex, account, derivationStrategy, opts) { - $.checkArgument(entropySourceHex); - $.shouldBeNumber(account); - $.checkArgument(_.contains(_.values(Constants.DERIVATION_STRATEGIES), derivationStrategy)); - - opts = opts || {}; - - var entropyBuffer = new Buffer(entropySourceHex, 'hex'); - //require at least 112 bits of entropy - $.checkArgument(entropyBuffer.length >= 14, 'At least 112 bits of entropy are needed') - - var x = new Credentials(); - x.xPubKey = xPubKey; - x.entropySource = Bitcore.crypto.Hash.sha256sha256(entropyBuffer).toString('hex'); - x.account = account; - x.derivationStrategy = derivationStrategy; - x.externalSource = source; - x._expand(); - return x; -}; - -// Get network from extended private key or extended public key -Credentials._getNetworkFromExtendedKey = function(xKey) { - $.checkArgument(xKey && _.isString(xKey)); - return xKey.charAt(0) == 't' ? 'testnet' : 'livenet'; -}; - -Credentials._xPubToCopayerId = function(xpub) { - var hash = sjcl.hash.sha256.hash(xpub); - return sjcl.codec.hex.fromBits(hash); -}; - -Credentials.prototype._hashFromEntropy = function(prefix, length) { - $.checkState(prefix); - var b = new Buffer(this.entropySource, 'hex'); - var b2 = Bitcore.crypto.Hash.sha256hmac(b, new Buffer(prefix)); - return b2.slice(0, length); -}; - - -Credentials.prototype._expand = function() { - $.checkState(this.xPrivKey || (this.xPubKey && this.entropySource)); - - var network = Credentials._getNetworkFromExtendedKey(this.xPrivKey || this.xPubKey); - if (this.network) { - $.checkState(this.network == network); - } else { - this.network = network; - } - - if (this.xPrivKey) { - var xPrivKey = new Bitcore.HDPrivateKey.fromString(this.xPrivKey); - - // this extra derivation is not to share a non hardened xPubKey to the server. - var addressDerivation = xPrivKey.derive(this.getBaseAddressDerivationPath()); - this.xPubKey = (new Bitcore.HDPublicKey(addressDerivation)).toString(); - - var requestDerivation = xPrivKey.derive(Constants.PATHS.REQUEST_KEY); - this.requestPrivKey = requestDerivation.privateKey.toString(); - - var pubKey = requestDerivation.publicKey; - this.requestPubKey = pubKey.toString(); - - this.entropySource = Bitcore.crypto.Hash.sha256(requestDerivation.privateKey.toBuffer()).toString('hex'); - } else { - var seed = this._hashFromEntropy('reqPrivKey', 32); - var privKey = new Bitcore.PrivateKey(seed.toString('hex'), network); - this.requestPrivKey = privKey.toString(); - this.requestPubKey = privKey.toPublicKey().toString(); - } - - this.personalEncryptingKey = this._hashFromEntropy('personalKey', 16).toString('base64'); - - - this.copayerId = Credentials._xPubToCopayerId(this.xPubKey); - this.publicKeyRing = [{ - xPubKey: this.xPubKey, - requestPubKey: this.requestPubKey, - }]; -}; - -Credentials.fromObj = function(obj) { - var x = new Credentials(); - - _.each(FIELDS, function(k) { - x[k] = obj[k]; - }); - - x.derivationStrategy = x.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45; - x.addressType = x.addressType || Constants.SCRIPT_TYPES.P2SH; - x.account = x.account || 0; - - $.checkState(x.xPrivKey || x.xPubKey || x.xPrivKeyEncrypted, "invalid input"); - return x; -}; - -Credentials.prototype.toObj = function() { - var self = this; - - var x = {}; - _.each(FIELDS, function(k) { - x[k] = self[k]; - }); - return x; -}; - -Credentials.prototype.getBaseAddressDerivationPath = function() { - var purpose; - switch (this.derivationStrategy) { - case Constants.DERIVATION_STRATEGIES.BIP45: - return "m/45'"; - case Constants.DERIVATION_STRATEGIES.BIP44: - purpose = '44'; - break; - case Constants.DERIVATION_STRATEGIES.BIP48: - purpose = '48'; - break; - } - - var coin = (this.network == 'livenet' ? "0" : "1"); - return "m/" + purpose + "'/" + coin + "'/" + this.account + "'"; -}; - -Credentials.prototype.getDerivedXPrivKey = function() { - var path = this.getBaseAddressDerivationPath(); - return new Bitcore.HDPrivateKey(this.xPrivKey, this.network).derive(path); -}; - -Credentials.prototype.addWalletPrivateKey = function(walletPrivKey) { - this.walletPrivKey = walletPrivKey; - this.sharedEncryptingKey = Utils.privateKeyToAESKey(walletPrivKey); -}; - -Credentials.prototype.addWalletInfo = function(walletId, walletName, m, n, copayerName) { - this.walletId = walletId; - this.walletName = walletName; - this.m = m; - this.n = n; - - if (copayerName) - this.copayerName = copayerName; - - if (this.derivationStrategy == 'BIP44' && n == 1) - this.addressType = Constants.SCRIPT_TYPES.P2PKH; - else - this.addressType = Constants.SCRIPT_TYPES.P2SH; - - // Use m/48' for multisig hardware wallets - if (!this.xPrivKey && this.externalSource && n > 1) { - this.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP48; - } - - if (n == 1) { - this.addPublicKeyRing([{ - xPubKey: this.xPubKey, - requestPubKey: this.requestPubKey, - }]); - } -}; - -Credentials.prototype.hasWalletInfo = function() { - return !!this.walletId; -}; - -Credentials.prototype.isPrivKeyEncrypted = function() { - return (!!this.xPrivKeyEncrypted) && !this.xPrivKey; -}; - -Credentials.prototype.hasPrivKeyEncrypted = function() { - return (!!this.xPrivKeyEncrypted); -}; - -Credentials.prototype.setPrivateKeyEncryption = function(password, opts) { - if (this.xPrivKeyEncrypted) - throw new Error('Encrypted Privkey Already exists'); - - if (!this.xPrivKey) - throw new Error('No private key to encrypt'); - - - this.xPrivKeyEncrypted = sjcl.encrypt(password, this.xPrivKey, opts); - if (!this.xPrivKeyEncrypted) - throw new Error('Could not encrypt'); - - if (this.mnemonic) - this.mnemonicEncrypted = sjcl.encrypt(password, this.mnemonic, opts); -}; - - -Credentials.prototype.disablePrivateKeyEncryption = function() { - if (!this.xPrivKeyEncrypted) - throw new Error('Private Key is not encrypted'); - - if (!this.xPrivKey) - throw new Error('Wallet is locked, cannot disable encryption'); - - this.xPrivKeyEncrypted = null; - this.mnemonicEncrypted = null; -}; - - -Credentials.prototype.lock = function() { - if (!this.xPrivKeyEncrypted) - throw new Error('Could not lock, no encrypted private key'); - - delete this.xPrivKey; - delete this.mnemonic; -}; - -Credentials.prototype.unlock = function(password) { - $.checkArgument(password); - - if (this.xPrivKeyEncrypted) { - this.xPrivKey = sjcl.decrypt(password, this.xPrivKeyEncrypted); - if (this.mnemonicEncrypted) { - this.mnemonic = sjcl.decrypt(password, this.mnemonicEncrypted); - } - } -}; - -Credentials.prototype.addPublicKeyRing = function(publicKeyRing) { - this.publicKeyRing = _.clone(publicKeyRing); -}; - -Credentials.prototype.canSign = function() { - return (!!this.xPrivKey || !!this.xPrivKeyEncrypted); -}; - -Credentials.prototype.setNoSign = function() { - delete this.xPrivKey; - delete this.xPrivKeyEncrypted; - delete this.mnemonic; - delete this.mnemonicEncrypted; -}; - -Credentials.prototype.isComplete = function() { - if (!this.m || !this.n) return false; - if (!this.publicKeyRing || this.publicKeyRing.length != this.n) return false; - return true; -}; - -Credentials.prototype.hasExternalSource = function() { - return (typeof this.externalSource == "string"); -}; - -Credentials.prototype.getExternalSourceName = function() { - return this.externalSource; -}; - -Credentials.prototype.getMnemonic = function() { - if (this.mnemonicEncrypted && !this.mnemonic) { - throw new Error('Credentials are encrypted'); - } - - return this.mnemonic; -}; - -Credentials.prototype.clearMnemonic = function() { - delete this.mnemonic; - delete this.mnemonicEncrypted; -}; - - -Credentials.fromOldCopayWallet = function(w) { - function walletPrivKeyFromOldCopayWallet(w) { - // IN BWS, the master Pub Keys are not sent to the server, - // so it is safe to use them as seed for wallet's shared secret. - var seed = w.publicKeyRing.copayersExtPubKeys.sort().join(''); - var seedBuf = new Buffer(seed); - var privKey = new Bitcore.PrivateKey.fromBuffer(Bitcore.crypto.Hash.sha256(seedBuf)); - return privKey.toString(); - }; - - var credentials = new Credentials(); - credentials.derivationStrategy = Constants.DERIVATION_STRATEGIES.BIP45; - credentials.xPrivKey = w.privateKey.extendedPrivateKeyString; - credentials._expand(); - - credentials.addWalletPrivateKey(walletPrivKeyFromOldCopayWallet(w)); - credentials.addWalletInfo(w.opts.id, w.opts.name, w.opts.requiredCopayers, w.opts.totalCopayers) - - var pkr = _.map(w.publicKeyRing.copayersExtPubKeys, function(xPubStr) { - - var isMe = xPubStr === credentials.xPubKey; - var requestDerivation; - - if (isMe) { - var path = Constants.PATHS.REQUEST_KEY; - requestDerivation = (new Bitcore.HDPrivateKey(credentials.xPrivKey)) - .derive(path).hdPublicKey; - } else { - // this - var path = Constants.PATHS.REQUEST_KEY_AUTH; - requestDerivation = (new Bitcore.HDPublicKey(xPubStr)).derive(path); - } - - // Grab Copayer Name - var hd = new Bitcore.HDPublicKey(xPubStr).derive('m/2147483646/0/0'); - var pubKey = hd.publicKey.toString('hex'); - var copayerName = w.publicKeyRing.nicknameFor[pubKey]; - if (isMe) { - credentials.copayerName = copayerName; - } - - return { - xPubKey: xPubStr, - requestPubKey: requestDerivation.publicKey.toString(), - copayerName: copayerName, - }; - }); - credentials.addPublicKeyRing(pkr); - return credentials; -}; - - -module.exports = Credentials; - -}).call(this,require("buffer").Buffer) -},{"./common":5,"bitcore-lib":64,"bitcore-mnemonic":136,"buffer":332,"lodash":179,"preconditions":180,"sjcl":313}],8:[function(require,module,exports){ -'use strict'; - -var _ = require('lodash'); - -function format(message, args) { - return message - .replace('{0}', args[0]) - .replace('{1}', args[1]) - .replace('{2}', args[2]); -} -var traverseNode = function(parent, errorDefinition) { - var NodeError = function() { - if (_.isString(errorDefinition.message)) { - this.message = format(errorDefinition.message, arguments); - } else if (_.isFunction(errorDefinition.message)) { - this.message = errorDefinition.message.apply(null, arguments); - } else { - throw new Error('Invalid error definition for ' + errorDefinition.name); - } - this.stack = this.message + '\n' + (new Error()).stack; - }; - NodeError.prototype = Object.create(parent.prototype); - NodeError.prototype.name = parent.prototype.name + errorDefinition.name; - parent[errorDefinition.name] = NodeError; - if (errorDefinition.errors) { - childDefinitions(NodeError, errorDefinition.errors); - } - return NodeError; -}; - -/* jshint latedef: false */ -var childDefinitions = function(parent, childDefinitions) { - _.each(childDefinitions, function(childDefinition) { - traverseNode(parent, childDefinition); - }); -}; -/* jshint latedef: true */ - -var traverseRoot = function(parent, errorsDefinition) { - childDefinitions(parent, errorsDefinition); - return parent; -}; - - -var bwc = {}; -bwc.Error = function() { - this.message = 'Internal error'; - this.stack = this.message + '\n' + (new Error()).stack; -}; -bwc.Error.prototype = Object.create(Error.prototype); -bwc.Error.prototype.name = 'bwc.Error'; - - -var data = require('./spec'); -traverseRoot(bwc.Error, data); - -module.exports = bwc.Error; - -module.exports.extend = function(spec) { - return traverseNode(bwc.Error, spec); -}; - -},{"./spec":9,"lodash":179}],9:[function(require,module,exports){ -'use strict'; - -var errorSpec = [{ - name: 'INVALID_BACKUP', - message: 'Invalid Backup' -}, { - name: 'WALLET_DOES_NOT_EXIST', - message: 'Wallet does not exist. Need to recreate' -}, { - name: 'MISSING_PRIVATE_KEY', - message: 'Missing private keys to sign' -}, { - name: 'ENCRYPTED_PRIVATE_KEY', - message: 'Private key is encrypted, cannot sign' -}, { - name: 'SERVER_COMPROMISED', - message: 'Server response could not be verified' -}, { - name: 'COULD_NOT_BUILD_TRANSACTION', - message: 'Could not build transaction' -}, { - name: 'INSUFFICIENT_FUNDS', - message: 'Insufficient funds' -}, { - name: 'CONNECTION_ERROR', - message: 'connection error' -}, { - name: 'NOT_FOUND', - message: 'not found' -}, { - name: 'ECONNRESET_ERROR', - message: 'ECONNRESET, body: {0}' -}, { - name: 'BAD_RESPONSE_CODE', - message: 'bad response code, code: {0}, body: {1}' -}, { - name: 'WALLET_ALREADY_EXISTS', - message: 'the wallet already exists' -}, { - name: 'COPAYER_IN_WALLET', - message: 'copayer in wallet' -}, { - name: 'WALLET_FULL', - message: 'wallet if full' -}, { - name: 'WALLET_NOT_FOUND', - message: 'wallet not found' -}, { - name: 'INSUFFICIENT_FUNDS_FOR_FEE', - message: 'insufficient funds for fee' -}, { - name: 'LOCKED_FUNDS', - message: 'locked funds' -}, { - name: 'COPAYER_VOTED', - message: 'Copayer already voted on this transaction proposal' -}, { - name: 'NOT_AUTHORIZED', - message: 'Copayer not found' -}, { - name: 'UNAVAILABLE_UTXOS', - message: 'Unavailable unspent outputs' -}, { - name: 'TX_NOT_FOUND', - message: 'transaction proposal not found' -} ]; - -module.exports = errorSpec; - -},{}],10:[function(require,module,exports){ -/** - * The official client library for bitcore-wallet-service. - * @module Client - */ - -/** - * Client API. - * @alias module:Client.API - */ -var client = module.exports = require('./api'); - -/** - * Verifier module. - * @alias module:Client.Verifier - */ -client.Verifier = require('./verifier'); -client.Utils = require('./common/utils'); -client.sjcl = require('sjcl'); - -// Expose bitcore -client.Bitcore = require('bitcore-lib'); - -},{"./api":2,"./common/utils":6,"./verifier":13,"bitcore-lib":64,"sjcl":313}],11:[function(require,module,exports){ -var _ = require('lodash'); -/** - * @desc - * A simple logger that wraps the console.log methods when available. - * - * Usage: - *
- *   log = new Logger('copay');
- *   log.setLevel('info');
- *   log.debug('Message!'); // won't show
- *   log.setLevel('debug');
- *   log.debug('Message!', 1); // will show '[debug] copay: Message!, 1'
- * 
- * - * @param {string} name - a name for the logger. This will show up on every log call - * @constructor - */ -var Logger = function(name) { - this.name = name || 'log'; - this.level = 2; -}; - -Logger.prototype.getLevels = function() { - return levels; -}; - - -var levels = { - 'debug': 0, - 'info': 1, - 'log': 2, - 'warn': 3, - 'error': 4, - 'fatal': 5 -}; - -_.each(levels, function(level, levelName) { - Logger.prototype[levelName] = function() { - if (level >= levels[this.level]) { - - if (Error.stackTraceLimit && this.level == 'debug') { - var old = Error.stackTraceLimit; - Error.stackTraceLimit = 2; - var stack; - - // this hack is to be compatible with IE11 - try { - anerror(); - } catch (e) { - stack = e.stack; - } - var lines = stack.split('\n'); - var caller = lines[2]; - caller = ':' + caller.substr(6); - Error.stackTraceLimit = old; - } - - var str = '[' + levelName + (caller || '') + '] ' + arguments[0], - extraArgs, - extraArgs = [].slice.call(arguments, 1); - if (console[levelName]) { - extraArgs.unshift(str); - console[levelName].apply(console, extraArgs); - } else { - if (extraArgs.length) { - str += JSON.stringify(extraArgs); - } - console.log(str); - } - } - }; -}); - -/** - * @desc - * Sets the level of a logger. A level can be any bewteen: 'debug', 'info', 'log', - * 'warn', 'error', and 'fatal'. That order matters: if a logger's level is set to - * 'warn', calling level.debug won't have any effect. - * - * @param {number} level - the name of the logging level - */ -Logger.prototype.setLevel = function(level) { - this.level = level; -}; - -/** - * @class Logger - * @method debug - * @desc Log messages at the debug level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method info - * @desc Log messages at the info level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method log - * @desc Log messages at an intermediary level called 'log'. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method warn - * @desc Log messages at the warn level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method error - * @desc Log messages at the error level. - * @param {*} args - the arguments to be logged. - */ -/** - * @class Logger - * @method fatal - * @desc Log messages at the fatal level. - * @param {*} args - the arguments to be logged. - */ - -var logger = new Logger('copay'); -var error = new Error(); -logger.setLevel('info'); -module.exports = logger; - -},{"lodash":179}],12:[function(require,module,exports){ -(function (process,Buffer){ -var $ = require('preconditions').singleton(); - -var Bitcore = require('bitcore-lib'); -var BitcorePayPro = require('bitcore-payment-protocol'); -var PayPro = {}; - -PayPro._nodeRequest = function(opts, cb) { - opts.agent = false; - var http = opts.httpNode || (opts.proto === 'http' ? require("http") : require("https")); - - var fn = opts.method == 'POST' ? 'post' : 'get'; - - http[fn](opts, function(res) { - if (res.statusCode != 200) - return cb(new Error('HTTP Request Error')); - - var data = []; // List of Buffer objects - res.on("data", function(chunk) { - data.push(chunk); // Append Buffer object - }); - res.on("end", function() { - data = Buffer.concat(data); // Make one large Buffer of it - return cb(null, data); - }); - }); -}; - -PayPro._browserRequest = function(opts, cb) { - var method = (opts.method || 'GET').toUpperCase(); - var url = opts.url; - var req = opts; - - req.headers = req.headers || {}; - req.body = req.body || req.data || ''; - - var xhr = opts.xhr || new XMLHttpRequest(); - xhr.open(method, url, true); - - Object.keys(req.headers).forEach(function(key) { - var val = req.headers[key]; - if (key === 'Content-Length') return; - if (key === 'Content-Transfer-Encoding') return; - xhr.setRequestHeader(key, val); - }); - xhr.responseType = 'arraybuffer'; - - xhr.onload = function(event) { - var response = xhr.response; - return cb(null, new Uint8Array(response)); - }; - - xhr.onerror = function(event) { - var status; - if (xhr.status === 0 || !xhr.statusText) { - status = 'HTTP Request Error'; - } else { - status = xhr.statusText; - } - return cb(new Error(status)); - }; - - if (req.body) { - xhr.send(req.body); - } else { - xhr.send(null); - } -}; - -var getHttp = function(opts) { - var match = opts.url.match(/^((http[s]?):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/); - - opts.proto = RegExp.$2; - opts.host = RegExp.$3; - opts.path = RegExp.$4 + RegExp.$6; - if (opts.http) return opts.http; - - var env = opts.env; - if (!env) - env = (process && !process.browser) ? 'node' : 'browser'; - - return (env == "node") ? PayPro._nodeRequest : http = PayPro._browserRequest;; -}; - -PayPro.get = function(opts, cb) { - $.checkArgument(opts && opts.url); - - var http = getHttp(opts); - opts.headers = opts.headers || { - 'Accept': BitcorePayPro.PAYMENT_REQUEST_CONTENT_TYPE, - 'Content-Type': 'application/octet-stream', - }; - - http(opts, function(err, dataBuffer) { - if (err) return cb(err); - var request, verified, signature, serializedDetails; - try { - var body = BitcorePayPro.PaymentRequest.decode(dataBuffer); - request = (new BitcorePayPro()).makePaymentRequest(body); - signature = request.get('signature'); - serializedDetails = request.get('serialized_payment_details'); - // Verify the signature - verified = request.verify(true); - } catch (e) { - return cb(new Error('Could not parse payment protocol: ' + e)); - } - - // Get the payment details - var decodedDetails = BitcorePayPro.PaymentDetails.decode(serializedDetails); - var pd = new BitcorePayPro(); - pd = pd.makePaymentDetails(decodedDetails); - - var outputs = pd.get('outputs'); - if (outputs.length > 1) - return cb(new Error('Payment Protocol Error: Requests with more that one output are not supported')) - - var output = outputs[0]; - - var amount = output.get('amount').toNumber(); - var network = pd.get('network') == 'test' ? 'testnet' : 'livenet'; - - // We love payment protocol - var offset = output.get('script').offset; - var limit = output.get('script').limit; - - // NOTE: For some reason output.script.buffer - // is only an ArrayBuffer - var buffer = new Buffer(new Uint8Array(output.get('script').buffer)); - var scriptBuf = buffer.slice(offset, limit); - var addr = new Bitcore.Address.fromScript(new Bitcore.Script(scriptBuf), network); - - var md = pd.get('merchant_data'); - - if (md) { - md = md.toString(); - } - - var ok = verified.verified; - var caName; - - if (verified.isChain) { - ok = ok && verified.chainVerified; - } - - return cb(null, { - verified: ok, - caTrusted: verified.caTrusted, - caName: verified.caName, - selfSigned: verified.selfSigned, - expires: pd.get('expires'), - memo: pd.get('memo'), - time: pd.get('time'), - merchant_data: md, - toAddress: addr.toString(), - amount: amount, - network: network, - domain: opts.host, - url: opts.url, - }); - }); -}; - - -PayPro._getPayProRefundOutputs = function(addrStr, amount) { - amount = amount.toString(10); - - var output = new BitcorePayPro.Output(); - var addr = new Bitcore.Address(addrStr); - - var s; - if (addr.isPayToPublicKeyHash()) { - s = Bitcore.Script.buildPublicKeyHashOut(addr); - } else if (addr.isPayToScriptHash()) { - s = Bitcore.Script.buildScriptHashOut(addr); - } else { - throw new Error('Unrecognized address type ' + addr.type); - } - - // console.log('PayPro refund address set to:', addrStr,s); - output.set('script', s.toBuffer()); - output.set('amount', amount); - return [output]; -}; - - -PayPro._createPayment = function(merchant_data, rawTx, refundAddr, amountSat) { - var pay = new BitcorePayPro(); - pay = pay.makePayment(); - - if (merchant_data) { - merchant_data = new Buffer(merchant_data); - pay.set('merchant_data', merchant_data); - } - - var txBuf = new Buffer(rawTx, 'hex'); - pay.set('transactions', [txBuf]); - - var refund_outputs = this._getPayProRefundOutputs(refundAddr, amountSat); - if (refund_outputs) - pay.set('refund_to', refund_outputs); - - // Unused for now - // options.memo = ''; - // pay.set('memo', options.memo); - - pay = pay.serialize(); - var buf = new ArrayBuffer(pay.length); - var view = new Uint8Array(buf); - for (var i = 0; i < pay.length; i++) { - view[i] = pay[i]; - } - - return view; -}; - -PayPro.send = function(opts, cb) { - $.checkArgument(opts.merchant_data) - .checkArgument(opts.url) - .checkArgument(opts.rawTx) - .checkArgument(opts.refundAddr) - .checkArgument(opts.amountSat); - - var payment = PayPro._createPayment(opts.merchant_data, opts.rawTx, opts.refundAddr, opts.amountSat); - - var http = getHttp(opts); - opts.method = 'POST'; - opts.headers = opts.headers || { - 'Accept': BitcorePayPro.PAYMENT_ACK_CONTENT_TYPE, - 'Content-Type': BitcorePayPro.PAYMENT_CONTENT_TYPE, - // 'Content-Type': 'application/octet-stream', - }; - opts.body = payment; - - http(opts, function(err, rawData) { - if (err) return cb(err); - var memo; - if (rawData) { - try { - var data = BitcorePayPro.PaymentACK.decode(rawData); - var pp = new BitcorePayPro(); - var ack = pp.makePaymentACK(data); - memo = ack.get('memo'); - } catch (e) {}; - } - return cb(null, rawData, memo); - }); -}; - -module.exports = PayPro; - -}).call(this,require('_process'),require("buffer").Buffer) -},{"_process":533,"bitcore-lib":64,"bitcore-payment-protocol":148,"buffer":332,"http":554,"https":529,"preconditions":180}],13:[function(require,module,exports){ -var $ = require('preconditions').singleton(); -var _ = require('lodash'); - -var Bitcore = require('bitcore-lib'); - -var Common = require('./common'); -var Utils = Common.Utils; - -var log = require('./log'); - -/** - * @desc Verifier constructor. Checks data given by the server - * - * @constructor - */ -function Verifier(opts) {}; - -/** - * Check address - * - * @param {Function} credentials - * @param {String} address - * @returns {Boolean} true or false - */ -Verifier.checkAddress = function(credentials, address) { - $.checkState(credentials.isComplete()); - - var local = Utils.deriveAddress(address.type || credentials.addressType, credentials.publicKeyRing, address.path, credentials.m, credentials.network); - return (local.address == address.address && - _.difference(local.publicKeys, address.publicKeys).length === 0); -}; - -/** - * Check copayers - * - * @param {Function} credentials - * @param {Array} copayers - * @returns {Boolean} true or false - */ -Verifier.checkCopayers = function(credentials, copayers) { - $.checkState(credentials.walletPrivKey); - var walletPubKey = Bitcore.PrivateKey.fromString(credentials.walletPrivKey).toPublicKey().toString(); - - if (copayers.length != credentials.n) { - log.error('Missing public keys in server response'); - return false; - } - - // Repeated xpub kes? - var uniq = []; - var error; - _.each(copayers, function(copayer) { - if (error) return; - - if (uniq[copayers.xPubKey]++) { - log.error('Repeated public keys in server response'); - error = true; - } - - // Not signed pub keys - if (!(copayer.encryptedName || copayer.name) || !copayer.xPubKey || !copayer.requestPubKey || !copayer.signature) { - log.error('Missing copayer fields in server response'); - error = true; - } else { - var hash = Utils.getCopayerHash(copayer.encryptedName || copayer.name, copayer.xPubKey, copayer.requestPubKey); - if (!Utils.verifyMessage(hash, copayer.signature, walletPubKey)) { - log.error('Invalid signatures in server response'); - error = true; - } - } - }); - - if (error) return false; - - if (!_.contains(_.pluck(copayers, 'xPubKey'), credentials.xPubKey)) { - log.error('Server response does not contains our public keys') - return false; - } - return true; -}; - -Verifier.checkProposalCreation = function(args, txp) { - function strEqual(str1, str2) { - return ((!str1 && !str2) || (str1 === str2)); - } - - if (txp.outputs.length != args.outputs.length) return false; - - for (var i = 0; i < txp.outputs.length; i++) { - var o1 = txp.outputs[i]; - var o2 = args.outputs[i]; - if (!strEqual(o1.toAddress, o2.toAddress)) return false; - if (!strEqual(o1.script, o2.script)) return false; - if (o1.amount != o2.amount) return false; - if (!strEqual(o1.message, o2.message)) return false; - } - - var changeAddress; - if (txp.changeAddress) { - changeAddress = txp.changeAddress.address; - } - - if (args.changeAddress && !strEqual(changeAddress, args.changeAddress)) return false; - if (_.isNumber(args.feePerKb) && (txp.feePerKb != args.feePerKb)) return false; - if (!strEqual(txp.payProUrl, args.payProUrl)) return false; - if (!strEqual(txp.message, args.message)) return false; - if (!_.isEqual(txp.customData, args.customData)) return false; - - return true; -}; - -Verifier.checkTxProposalSignature = function(credentials, txp) { - $.checkArgument(txp.creatorId); - $.checkState(credentials.isComplete()); - - var creatorKeys = _.find(credentials.publicKeyRing, function(item) { - if (Utils.xPubToCopayerId(item.xPubKey) === txp.creatorId) return true; - }); - - if (!creatorKeys) return false; - var creatorSigningPubKey; - - // If the txp using a selfsigned pub key? - if (txp.proposalSignaturePubKey) { - - // Verify it... - if (!Utils.verifyRequestPubKey(txp.proposalSignaturePubKey, txp.proposalSignaturePubKeySig, creatorKeys.xPubKey)) - return false; - - creatorSigningPubKey = txp.proposalSignaturePubKey; - } else { - creatorSigningPubKey = creatorKeys.requestPubKey; - } - if (!creatorSigningPubKey) return false; - - - var hash; - if (parseInt(txp.version) >= 3) { - var t = Utils.buildTx(txp); - hash = t.uncheckedSerialize(); - } else { - if (txp.outputs) { - var outputs = _.map(txp.outputs, function(o) { - return { - toAddress: o.toAddress, - amount: o.amount, - message: o.encryptedMessage || o.message || null - }; - }); - var proposalHeader = { - outputs: outputs, - message: txp.encryptedMessage || txp.message || null, - payProUrl: txp.payProUrl || null, - }; - hash = Utils.getProposalHash(proposalHeader); - } else { - hash = Utils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message || null, txp.payProUrl || null); - } - } - - log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); - if (!Utils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) - return false; - - if (!Verifier.checkAddress(credentials, txp.changeAddress)) - return false; - - return true; -}; - - -Verifier.checkPaypro = function(txp, payproOpts) { - var toAddress, amount; - - if (parseInt(txp.version) >= 3) { - toAddress = txp.outputs[0].toAddress; - amount = txp.amount; - } else { - toAddress = txp.toAddress; - amount = txp.amount; - } - - return (toAddress == payproOpts.toAddress && amount == payproOpts.amount); -}; - - -/** - * Check transaction proposal - * - * @param {Function} credentials - * @param {Object} txp - * @param {Object} Optional: paypro - * @param {Boolean} isLegit - */ -Verifier.checkTxProposal = function(credentials, txp, opts) { - opts = opts || {}; - - if (!this.checkTxProposalSignature(credentials, txp)) - return false; - - if (opts.paypro && !this.checkPaypro(txp, opts.paypro)) - return false; - - return true; -}; - -module.exports = Verifier; - -},{"./common":5,"./log":11,"bitcore-lib":64,"lodash":179,"preconditions":180}],14:[function(require,module,exports){ -(function (process){ -/*! - * async - * https://github.com/caolan/async - * - * Copyright 2010-2014 Caolan McMahon - * Released under the MIT license - */ -/*jshint onevar: false, indent:4 */ -/*global setImmediate: false, setTimeout: false, console: false */ -(function () { - - var async = {}; - - // global on the server, window in the browser - var root, previous_async; - - root = this; - if (root != null) { - previous_async = root.async; - } - - async.noConflict = function () { - root.async = previous_async; - return async; - }; - - function only_once(fn) { - var called = false; - return function() { - if (called) throw new Error("Callback was already called."); - called = true; - fn.apply(root, arguments); - } - } - - //// cross-browser compatiblity functions //// - - var _toString = Object.prototype.toString; - - var _isArray = Array.isArray || function (obj) { - return _toString.call(obj) === '[object Array]'; - }; - - var _each = function (arr, iterator) { - for (var i = 0; i < arr.length; i += 1) { - iterator(arr[i], i, arr); - } - }; - - var _map = function (arr, iterator) { - if (arr.map) { - return arr.map(iterator); - } - var results = []; - _each(arr, function (x, i, a) { - results.push(iterator(x, i, a)); - }); - return results; - }; - - var _reduce = function (arr, iterator, memo) { - if (arr.reduce) { - return arr.reduce(iterator, memo); - } - _each(arr, function (x, i, a) { - memo = iterator(memo, x, i, a); - }); - return memo; - }; - - var _keys = function (obj) { - if (Object.keys) { - return Object.keys(obj); - } - var keys = []; - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - keys.push(k); - } - } - return keys; - }; - - //// exported async module functions //// - - //// nextTick implementation with browser-compatible fallback //// - if (typeof process === 'undefined' || !(process.nextTick)) { - if (typeof setImmediate === 'function') { - async.nextTick = function (fn) { - // not a direct alias for IE10 compatibility - setImmediate(fn); - }; - async.setImmediate = async.nextTick; - } - else { - async.nextTick = function (fn) { - setTimeout(fn, 0); - }; - async.setImmediate = async.nextTick; - } - } - else { - async.nextTick = process.nextTick; - if (typeof setImmediate !== 'undefined') { - async.setImmediate = function (fn) { - // not a direct alias for IE10 compatibility - setImmediate(fn); - }; - } - else { - async.setImmediate = async.nextTick; - } - } - - async.each = function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length) { - return callback(); - } - var completed = 0; - _each(arr, function (x) { - iterator(x, only_once(done) ); - }); - function done(err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - if (completed >= arr.length) { - callback(); - } - } - } - }; - async.forEach = async.each; - - async.eachSeries = function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length) { - return callback(); - } - var completed = 0; - var iterate = function () { - iterator(arr[completed], function (err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - if (completed >= arr.length) { - callback(); - } - else { - iterate(); - } - } - }); - }; - iterate(); - }; - async.forEachSeries = async.eachSeries; - - async.eachLimit = function (arr, limit, iterator, callback) { - var fn = _eachLimit(limit); - fn.apply(null, [arr, iterator, callback]); - }; - async.forEachLimit = async.eachLimit; - - var _eachLimit = function (limit) { - - return function (arr, iterator, callback) { - callback = callback || function () {}; - if (!arr.length || limit <= 0) { - return callback(); - } - var completed = 0; - var started = 0; - var running = 0; - - (function replenish () { - if (completed >= arr.length) { - return callback(); - } - - while (running < limit && started < arr.length) { - started += 1; - running += 1; - iterator(arr[started - 1], function (err) { - if (err) { - callback(err); - callback = function () {}; - } - else { - completed += 1; - running -= 1; - if (completed >= arr.length) { - callback(); - } - else { - replenish(); - } - } - }); - } - })(); - }; - }; - - - var doParallel = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [async.each].concat(args)); - }; - }; - var doParallelLimit = function(limit, fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [_eachLimit(limit)].concat(args)); - }; - }; - var doSeries = function (fn) { - return function () { - var args = Array.prototype.slice.call(arguments); - return fn.apply(null, [async.eachSeries].concat(args)); - }; - }; - - - var _asyncMap = function (eachfn, arr, iterator, callback) { - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - if (!callback) { - eachfn(arr, function (x, callback) { - iterator(x.value, function (err) { - callback(err); - }); - }); - } else { - var results = []; - eachfn(arr, function (x, callback) { - iterator(x.value, function (err, v) { - results[x.index] = v; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - async.map = doParallel(_asyncMap); - async.mapSeries = doSeries(_asyncMap); - async.mapLimit = function (arr, limit, iterator, callback) { - return _mapLimit(limit)(arr, iterator, callback); - }; - - var _mapLimit = function(limit) { - return doParallelLimit(limit, _asyncMap); - }; - - // reduce only has a series version, as doing reduce in parallel won't - // work in many situations. - async.reduce = function (arr, memo, iterator, callback) { - async.eachSeries(arr, function (x, callback) { - iterator(memo, x, function (err, v) { - memo = v; - callback(err); - }); - }, function (err) { - callback(err, memo); - }); - }; - // inject alias - async.inject = async.reduce; - // foldl alias - async.foldl = async.reduce; - - async.reduceRight = function (arr, memo, iterator, callback) { - var reversed = _map(arr, function (x) { - return x; - }).reverse(); - async.reduce(reversed, memo, iterator, callback); - }; - // foldr alias - async.foldr = async.reduceRight; - - var _filter = function (eachfn, arr, iterator, callback) { - var results = []; - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - eachfn(arr, function (x, callback) { - iterator(x.value, function (v) { - if (v) { - results.push(x); - } - callback(); - }); - }, function (err) { - callback(_map(results.sort(function (a, b) { - return a.index - b.index; - }), function (x) { - return x.value; - })); - }); - }; - async.filter = doParallel(_filter); - async.filterSeries = doSeries(_filter); - // select alias - async.select = async.filter; - async.selectSeries = async.filterSeries; - - var _reject = function (eachfn, arr, iterator, callback) { - var results = []; - arr = _map(arr, function (x, i) { - return {index: i, value: x}; - }); - eachfn(arr, function (x, callback) { - iterator(x.value, function (v) { - if (!v) { - results.push(x); - } - callback(); - }); - }, function (err) { - callback(_map(results.sort(function (a, b) { - return a.index - b.index; - }), function (x) { - return x.value; - })); - }); - }; - async.reject = doParallel(_reject); - async.rejectSeries = doSeries(_reject); - - var _detect = function (eachfn, arr, iterator, main_callback) { - eachfn(arr, function (x, callback) { - iterator(x, function (result) { - if (result) { - main_callback(x); - main_callback = function () {}; - } - else { - callback(); - } - }); - }, function (err) { - main_callback(); - }); - }; - async.detect = doParallel(_detect); - async.detectSeries = doSeries(_detect); - - async.some = function (arr, iterator, main_callback) { - async.each(arr, function (x, callback) { - iterator(x, function (v) { - if (v) { - main_callback(true); - main_callback = function () {}; - } - callback(); - }); - }, function (err) { - main_callback(false); - }); - }; - // any alias - async.any = async.some; - - async.every = function (arr, iterator, main_callback) { - async.each(arr, function (x, callback) { - iterator(x, function (v) { - if (!v) { - main_callback(false); - main_callback = function () {}; - } - callback(); - }); - }, function (err) { - main_callback(true); - }); - }; - // all alias - async.all = async.every; - - async.sortBy = function (arr, iterator, callback) { - async.map(arr, function (x, callback) { - iterator(x, function (err, criteria) { - if (err) { - callback(err); - } - else { - callback(null, {value: x, criteria: criteria}); - } - }); - }, function (err, results) { - if (err) { - return callback(err); - } - else { - var fn = function (left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }; - callback(null, _map(results.sort(fn), function (x) { - return x.value; - })); - } - }); - }; - - async.auto = function (tasks, callback) { - callback = callback || function () {}; - var keys = _keys(tasks); - var remainingTasks = keys.length - if (!remainingTasks) { - return callback(); - } - - var results = {}; - - var listeners = []; - var addListener = function (fn) { - listeners.unshift(fn); - }; - var removeListener = function (fn) { - for (var i = 0; i < listeners.length; i += 1) { - if (listeners[i] === fn) { - listeners.splice(i, 1); - return; - } - } - }; - var taskComplete = function () { - remainingTasks-- - _each(listeners.slice(0), function (fn) { - fn(); - }); - }; - - addListener(function () { - if (!remainingTasks) { - var theCallback = callback; - // prevent final callback from calling itself if it errors - callback = function () {}; - - theCallback(null, results); - } - }); - - _each(keys, function (k) { - var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; - var taskCallback = function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - if (err) { - var safeResults = {}; - _each(_keys(results), function(rkey) { - safeResults[rkey] = results[rkey]; - }); - safeResults[k] = args; - callback(err, safeResults); - // stop subsequent errors hitting callback multiple times - callback = function () {}; - } - else { - results[k] = args; - async.setImmediate(taskComplete); - } - }; - var requires = task.slice(0, Math.abs(task.length - 1)) || []; - var ready = function () { - return _reduce(requires, function (a, x) { - return (a && results.hasOwnProperty(x)); - }, true) && !results.hasOwnProperty(k); - }; - if (ready()) { - task[task.length - 1](taskCallback, results); - } - else { - var listener = function () { - if (ready()) { - removeListener(listener); - task[task.length - 1](taskCallback, results); - } - }; - addListener(listener); - } - }); - }; - - async.retry = function(times, task, callback) { - var DEFAULT_TIMES = 5; - var attempts = []; - // Use defaults if times not passed - if (typeof times === 'function') { - callback = task; - task = times; - times = DEFAULT_TIMES; - } - // Make sure times is a number - times = parseInt(times, 10) || DEFAULT_TIMES; - var wrappedTask = function(wrappedCallback, wrappedResults) { - var retryAttempt = function(task, finalAttempt) { - return function(seriesCallback) { - task(function(err, result){ - seriesCallback(!err || finalAttempt, {err: err, result: result}); - }, wrappedResults); - }; - }; - while (times) { - attempts.push(retryAttempt(task, !(times-=1))); - } - async.series(attempts, function(done, data){ - data = data[data.length - 1]; - (wrappedCallback || callback)(data.err, data.result); - }); - } - // If a callback is passed, run this as a controll flow - return callback ? wrappedTask() : wrappedTask - }; - - async.waterfall = function (tasks, callback) { - callback = callback || function () {}; - if (!_isArray(tasks)) { - var err = new Error('First argument to waterfall must be an array of functions'); - return callback(err); - } - if (!tasks.length) { - return callback(); - } - var wrapIterator = function (iterator) { - return function (err) { - if (err) { - callback.apply(null, arguments); - callback = function () {}; - } - else { - var args = Array.prototype.slice.call(arguments, 1); - var next = iterator.next(); - if (next) { - args.push(wrapIterator(next)); - } - else { - args.push(callback); - } - async.setImmediate(function () { - iterator.apply(null, args); - }); - } - }; - }; - wrapIterator(async.iterator(tasks))(); - }; - - var _parallel = function(eachfn, tasks, callback) { - callback = callback || function () {}; - if (_isArray(tasks)) { - eachfn.map(tasks, function (fn, callback) { - if (fn) { - fn(function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - callback.call(null, err, args); - }); - } - }, callback); - } - else { - var results = {}; - eachfn.each(_keys(tasks), function (k, callback) { - tasks[k](function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - results[k] = args; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - - async.parallel = function (tasks, callback) { - _parallel({ map: async.map, each: async.each }, tasks, callback); - }; - - async.parallelLimit = function(tasks, limit, callback) { - _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); - }; - - async.series = function (tasks, callback) { - callback = callback || function () {}; - if (_isArray(tasks)) { - async.mapSeries(tasks, function (fn, callback) { - if (fn) { - fn(function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - callback.call(null, err, args); - }); - } - }, callback); - } - else { - var results = {}; - async.eachSeries(_keys(tasks), function (k, callback) { - tasks[k](function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (args.length <= 1) { - args = args[0]; - } - results[k] = args; - callback(err); - }); - }, function (err) { - callback(err, results); - }); - } - }; - - async.iterator = function (tasks) { - var makeCallback = function (index) { - var fn = function () { - if (tasks.length) { - tasks[index].apply(null, arguments); - } - return fn.next(); - }; - fn.next = function () { - return (index < tasks.length - 1) ? makeCallback(index + 1): null; - }; - return fn; - }; - return makeCallback(0); - }; - - async.apply = function (fn) { - var args = Array.prototype.slice.call(arguments, 1); - return function () { - return fn.apply( - null, args.concat(Array.prototype.slice.call(arguments)) - ); - }; - }; - - var _concat = function (eachfn, arr, fn, callback) { - var r = []; - eachfn(arr, function (x, cb) { - fn(x, function (err, y) { - r = r.concat(y || []); - cb(err); - }); - }, function (err) { - callback(err, r); - }); - }; - async.concat = doParallel(_concat); - async.concatSeries = doSeries(_concat); - - async.whilst = function (test, iterator, callback) { - if (test()) { - iterator(function (err) { - if (err) { - return callback(err); - } - async.whilst(test, iterator, callback); - }); - } - else { - callback(); - } - }; - - async.doWhilst = function (iterator, test, callback) { - iterator(function (err) { - if (err) { - return callback(err); - } - var args = Array.prototype.slice.call(arguments, 1); - if (test.apply(null, args)) { - async.doWhilst(iterator, test, callback); - } - else { - callback(); - } - }); - }; - - async.until = function (test, iterator, callback) { - if (!test()) { - iterator(function (err) { - if (err) { - return callback(err); - } - async.until(test, iterator, callback); - }); - } - else { - callback(); - } - }; - - async.doUntil = function (iterator, test, callback) { - iterator(function (err) { - if (err) { - return callback(err); - } - var args = Array.prototype.slice.call(arguments, 1); - if (!test.apply(null, args)) { - async.doUntil(iterator, test, callback); - } - else { - callback(); - } - }); - }; - - async.queue = function (worker, concurrency) { - if (concurrency === undefined) { - concurrency = 1; - } - function _insert(q, data, pos, callback) { - if (!q.started){ - q.started = true; - } - if (!_isArray(data)) { - data = [data]; - } - if(data.length == 0) { - // call drain immediately if there are no tasks - return async.setImmediate(function() { - if (q.drain) { - q.drain(); - } - }); - } - _each(data, function(task) { - var item = { - data: task, - callback: typeof callback === 'function' ? callback : null - }; - - if (pos) { - q.tasks.unshift(item); - } else { - q.tasks.push(item); - } - - if (q.saturated && q.tasks.length === q.concurrency) { - q.saturated(); - } - async.setImmediate(q.process); - }); - } - - var workers = 0; - var q = { - tasks: [], - concurrency: concurrency, - saturated: null, - empty: null, - drain: null, - started: false, - paused: false, - push: function (data, callback) { - _insert(q, data, false, callback); - }, - kill: function () { - q.drain = null; - q.tasks = []; - }, - unshift: function (data, callback) { - _insert(q, data, true, callback); - }, - process: function () { - if (!q.paused && workers < q.concurrency && q.tasks.length) { - var task = q.tasks.shift(); - if (q.empty && q.tasks.length === 0) { - q.empty(); - } - workers += 1; - var next = function () { - workers -= 1; - if (task.callback) { - task.callback.apply(task, arguments); - } - if (q.drain && q.tasks.length + workers === 0) { - q.drain(); - } - q.process(); - }; - var cb = only_once(next); - worker(task.data, cb); - } - }, - length: function () { - return q.tasks.length; - }, - running: function () { - return workers; - }, - idle: function() { - return q.tasks.length + workers === 0; - }, - pause: function () { - if (q.paused === true) { return; } - q.paused = true; - }, - resume: function () { - if (q.paused === false) { return; } - q.paused = false; - // Need to call q.process once per concurrent - // worker to preserve full concurrency after pause - for (var w = 1; w <= q.concurrency; w++) { - async.setImmediate(q.process); - } - } - }; - return q; - }; - - async.priorityQueue = function (worker, concurrency) { - - function _compareTasks(a, b){ - return a.priority - b.priority; - }; - - function _binarySearch(sequence, item, compare) { - var beg = -1, - end = sequence.length - 1; - while (beg < end) { - var mid = beg + ((end - beg + 1) >>> 1); - if (compare(item, sequence[mid]) >= 0) { - beg = mid; - } else { - end = mid - 1; - } - } - return beg; - } - - function _insert(q, data, priority, callback) { - if (!q.started){ - q.started = true; - } - if (!_isArray(data)) { - data = [data]; - } - if(data.length == 0) { - // call drain immediately if there are no tasks - return async.setImmediate(function() { - if (q.drain) { - q.drain(); - } - }); - } - _each(data, function(task) { - var item = { - data: task, - priority: priority, - callback: typeof callback === 'function' ? callback : null - }; - - q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); - - if (q.saturated && q.tasks.length === q.concurrency) { - q.saturated(); - } - async.setImmediate(q.process); - }); - } - - // Start with a normal queue - var q = async.queue(worker, concurrency); - - // Override push to accept second parameter representing priority - q.push = function (data, priority, callback) { - _insert(q, data, priority, callback); - }; - - // Remove unshift function - delete q.unshift; - - return q; - }; - - async.cargo = function (worker, payload) { - var working = false, - tasks = []; - - var cargo = { - tasks: tasks, - payload: payload, - saturated: null, - empty: null, - drain: null, - drained: true, - push: function (data, callback) { - if (!_isArray(data)) { - data = [data]; - } - _each(data, function(task) { - tasks.push({ - data: task, - callback: typeof callback === 'function' ? callback : null - }); - cargo.drained = false; - if (cargo.saturated && tasks.length === payload) { - cargo.saturated(); - } - }); - async.setImmediate(cargo.process); - }, - process: function process() { - if (working) return; - if (tasks.length === 0) { - if(cargo.drain && !cargo.drained) cargo.drain(); - cargo.drained = true; - return; - } - - var ts = typeof payload === 'number' - ? tasks.splice(0, payload) - : tasks.splice(0, tasks.length); - - var ds = _map(ts, function (task) { - return task.data; - }); - - if(cargo.empty) cargo.empty(); - working = true; - worker(ds, function () { - working = false; - - var args = arguments; - _each(ts, function (data) { - if (data.callback) { - data.callback.apply(null, args); - } - }); - - process(); - }); - }, - length: function () { - return tasks.length; - }, - running: function () { - return working; - } - }; - return cargo; - }; - - var _console_fn = function (name) { - return function (fn) { - var args = Array.prototype.slice.call(arguments, 1); - fn.apply(null, args.concat([function (err) { - var args = Array.prototype.slice.call(arguments, 1); - if (typeof console !== 'undefined') { - if (err) { - if (console.error) { - console.error(err); - } - } - else if (console[name]) { - _each(args, function (x) { - console[name](x); - }); - } - } - }])); - }; - }; - async.log = _console_fn('log'); - async.dir = _console_fn('dir'); - /*async.info = _console_fn('info'); - async.warn = _console_fn('warn'); - async.error = _console_fn('error');*/ - - async.memoize = function (fn, hasher) { - var memo = {}; - var queues = {}; - hasher = hasher || function (x) { - return x; - }; - var memoized = function () { - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - var key = hasher.apply(null, args); - if (key in memo) { - async.nextTick(function () { - callback.apply(null, memo[key]); - }); - } - else if (key in queues) { - queues[key].push(callback); - } - else { - queues[key] = [callback]; - fn.apply(null, args.concat([function () { - memo[key] = arguments; - var q = queues[key]; - delete queues[key]; - for (var i = 0, l = q.length; i < l; i++) { - q[i].apply(null, arguments); - } - }])); - } - }; - memoized.memo = memo; - memoized.unmemoized = fn; - return memoized; - }; - - async.unmemoize = function (fn) { - return function () { - return (fn.unmemoized || fn).apply(null, arguments); - }; - }; - - async.times = function (count, iterator, callback) { - var counter = []; - for (var i = 0; i < count; i++) { - counter.push(i); - } - return async.map(counter, iterator, callback); - }; - - async.timesSeries = function (count, iterator, callback) { - var counter = []; - for (var i = 0; i < count; i++) { - counter.push(i); - } - return async.mapSeries(counter, iterator, callback); - }; - - async.seq = function (/* functions... */) { - var fns = arguments; - return function () { - var that = this; - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - async.reduce(fns, args, function (newargs, fn, cb) { - fn.apply(that, newargs.concat([function () { - var err = arguments[0]; - var nextargs = Array.prototype.slice.call(arguments, 1); - cb(err, nextargs); - }])) - }, - function (err, results) { - callback.apply(that, [err].concat(results)); - }); - }; - }; - - async.compose = function (/* functions... */) { - return async.seq.apply(null, Array.prototype.reverse.call(arguments)); - }; - - var _applyEach = function (eachfn, fns /*args...*/) { - var go = function () { - var that = this; - var args = Array.prototype.slice.call(arguments); - var callback = args.pop(); - return eachfn(fns, function (fn, cb) { - fn.apply(that, args.concat([cb])); - }, - callback); - }; - if (arguments.length > 2) { - var args = Array.prototype.slice.call(arguments, 2); - return go.apply(this, args); - } - else { - return go; - } - }; - async.applyEach = doParallel(_applyEach); - async.applyEachSeries = doSeries(_applyEach); - - async.forever = function (fn, callback) { - function next(err) { - if (err) { - if (callback) { - return callback(err); - } - throw err; - } - fn(next); - } - next(); - }; - - // Node.js - if (typeof module !== 'undefined' && module.exports) { - module.exports = async; - } - // AMD / RequireJS - else if (typeof define !== 'undefined' && define.amd) { - define([], function () { - return async; - }); - } - // included directly via