diff --git a/.travis.yml b/.travis.yml index fdf9bd708..979a61bed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ env: script: - make -- make test GOFLAGS="-race" +- make test GOFLAGS="-timeout 20m -race -v" - make coverage after_success: diff --git a/Makefile b/Makefile index 57bdf888e..f9eb341fa 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ spelling: test: build @echo "Running all minio testing:" + @go test $(GOFLAGS) . @go test $(GOFLAGS) github.com/minio/minio/cmd... @go test $(GOFLAGS) github.com/minio/minio/pkg... diff --git a/README.md b/README.md index 82b508ecb..1f2540c6c 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ chmod 755 minio |GNU/Linux|64-bit Intel|https://dl.minio.io/server/minio/release/linux-amd64/minio| ||32-bit Intel|https://dl.minio.io/server/minio/release/linux-386/minio| ||32-bit ARM|https://dl.minio.io/server/minio/release/linux-arm/minio| +||64-bit ARM|https://dl.minio.io/server/minio/release/linux-arm64/minio| +||32-bit ARMv6|https://dl.minio.io/server/minio/release/linux-arm6vl/minio| ```sh chmod +x minio ./minio server ~/Photos diff --git a/README_ZH.md b/README_ZH.md index 8e911a4ae..05d463920 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -11,6 +11,8 @@ Minio是一个非常轻量的服务,可以很简单的和其他应用的结合 |GNU/Linux|64-bit Intel|https://dl.minio.io/server/minio/release/linux-amd64/minio| ||32-bit Intel|https://dl.minio.io/server/minio/release/linux-386/minio| ||32-bit ARM|https://dl.minio.io/server/minio/release/linux-arm/minio| +||64-bit ARM|https://dl.minio.io/server/minio/release/linux-arm64/minio| +||32-bit ARMv6|https://dl.minio.io/server/minio/release/linux-arm6vl/minio| |Apple OS X|64-bit Intel|https://dl.minio.io/server/minio/release/darwin-amd64/minio| |Microsoft Windows|64-bit|https://dl.minio.io/server/minio/release/windows-amd64/minio.exe| ||32-bit|https://dl.minio.io/server/minio/release/windows-386/minio.exe| diff --git a/appveyor.yml b/appveyor.yml index 7488c103a..68a87aa07 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,9 +35,9 @@ test_script: # Unit tests - ps: Add-AppveyorTest "Unit Tests" -Outcome Running - mkdir build\coverage - - go test -timeout 15m -v -race github.com/minio/minio/cmd... + - go test -timeout 20m -v -race github.com/minio/minio/cmd... - go test -v -race github.com/minio/minio/pkg... - - go test -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd + - go test -timeout 15m -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd - ps: Update-AppveyorTest "Unit Tests" -Outcome Passed after_test: diff --git a/browser/README.md b/browser/README.md index 74bb563f2..647147fdf 100644 --- a/browser/README.md +++ b/browser/README.md @@ -4,34 +4,69 @@ ## Installation -### Install yarn: +### Install yarn ```sh -$ curl -o- -L https://yarnpkg.com/install.sh | bash -$ yarn +curl -o- -L https://yarnpkg.com/install.sh | bash +yarn ``` -### Install `go-bindata` and `go-bindata-assetfs`. +### Install `go-bindata` and `go-bindata-assetfs` If you do not have a working Golang environment, please follow [Install Golang](https://docs.minio.io/docs/how-to-install-golang) ```sh -$ go get github.com/jteeuwen/go-bindata/... -$ go get github.com/elazarl/go-bindata-assetfs/... +go get github.com/jteeuwen/go-bindata/... +go get github.com/elazarl/go-bindata-assetfs/... ``` -## Generating Assets. +## Generating Assets ### Generate ui-assets.go ```sh -$ yarn release +yarn release ``` -This generates ui-assets.go in the current direcotry. Now do `make` in the parent directory to build the minio binary with the newly generated ui-assets.go -### Run Minio Browser with live reload. +This generates ui-assets.go in the current direcotry. Now do `make` in the parent directory to build the minio binary with the newly generated ``ui-assets.go`` + +### Run Minio Browser with live reload ```sh -$ yarn dev +yarn dev ``` Open [http://localhost:8080/minio/](http://localhost:8080/minio/) in your browser to play with the application + +### Run Minio Browser with live reload on custom port + +Edit `browser/webpack.config.js` + +```diff +diff --git a/browser/webpack.config.js b/browser/webpack.config.js +index 3ccdaba..9496c56 100644 +--- a/browser/webpack.config.js ++++ b/browser/webpack.config.js +@@ -58,6 +58,7 @@ var exports = { + historyApiFallback: { + index: '/minio/' + }, ++ port: 8888, + proxy: { + '/minio/webrpc': { + target: 'http://localhost:9000', +@@ -97,7 +98,7 @@ var exports = { + if (process.env.NODE_ENV === 'dev') { + exports.entry = [ + 'webpack/hot/dev-server', +- 'webpack-dev-server/client?http://localhost:8080', ++ 'webpack-dev-server/client?http://localhost:8888', + path.resolve(__dirname, 'app/index.js') + ] + } +``` + +```sh +yarn dev +``` + +Open [http://localhost:8888/minio/](http://localhost:8888/minio/) in your browser to play with the application diff --git a/browser/app/js/actions.js b/browser/app/js/actions.js index 979f1ad97..c9b2f72bf 100644 --- a/browser/app/js/actions.js +++ b/browser/app/js/actions.js @@ -56,6 +56,7 @@ export const SET_POLICIES = 'SET_POLICIES' export const SET_SHARE_OBJECT = 'SET_SHARE_OBJECT' export const DELETE_CONFIRMATION = 'DELETE_CONFIRMATION' export const SET_PREFIX_WRITABLE = 'SET_PREFIX_WRITABLE' +export const REMOVE_OBJECT = 'REMOVE_OBJECT' export const showDeleteConfirmation = (object) => { return { @@ -206,6 +207,13 @@ export const showAlert = alert => { } } +export const removeObject = object => { + return { + type: REMOVE_OBJECT, + object + } +} + export const setSidebarStatus = (status) => { return { type: SET_SIDEBAR_STATUS, @@ -227,10 +235,12 @@ export const setVisibleBuckets = visibleBuckets => { } } -export const setObjects = (objects) => { +export const setObjects = (objects, marker, istruncated) => { return { type: SET_OBJECTS, - objects + objects, + marker, + istruncated } } @@ -284,22 +294,63 @@ export const selectBucket = (newCurrentBucket, prefix) => { } } +export const listObjects = () => { + return (dispatch, getState) => { + const {currentBucket, currentPath, marker, objects, istruncated, web} = getState() + if (!istruncated) return + web.ListObjects({ + bucketName: currentBucket, + prefix: currentPath, + marker: marker + }) + .then(res => { + let objects = res.objects + if (!objects) + objects = [] + objects = objects.map(object => { + object.name = object.name.replace(`${currentPath}`, ''); + return object + }) + dispatch(setObjects(objects, res.nextmarker, res.istruncated)) + dispatch(setPrefixWritable(res.writable)) + dispatch(setLoadBucket('')) + dispatch(setLoadPath('')) + }) + .catch(err => { + dispatch(showAlert({ + type: 'danger', + message: err.message + })) + dispatch(setLoadBucket('')) + dispatch(setLoadPath('')) + // Use browserHistory.replace instead of push so that browser back button works fine. + browserHistory.replace(`${minioBrowserPrefix}/login`) + }) + } +} + export const selectPrefix = prefix => { return (dispatch, getState) => { const {currentBucket, web} = getState() + dispatch(setObjects([], "", false)) dispatch(setLoadPath(prefix)) web.ListObjects({ bucketName: currentBucket, - prefix + prefix, + marker: "" }) .then(res => { let objects = res.objects if (!objects) objects = [] + objects = objects.map(object => { + object.name = object.name.replace(`${prefix}`, ''); + return object + }) dispatch(setObjects( - utils.sortObjectsByName(objects.map(object => { - object.name = object.name.replace(`${prefix}`, ''); return object - })) + objects, + res.nextmarker, + res.istruncated )) dispatch(setPrefixWritable(res.writable)) dispatch(setSortNameOrder(false)) @@ -314,8 +365,8 @@ export const selectPrefix = prefix => { })) dispatch(setLoadBucket('')) dispatch(setLoadPath('')) - // Use browserHistory.replace instead of push so that browser back button works fine. - browserHistory.replace(`${minioBrowserPrefix}/login`) + // Use browserHistory.replace instead of push so that browser back button works fine. + browserHistory.replace(`${minioBrowserPrefix}/login`) }) } } diff --git a/browser/app/js/components/Browse.js b/browser/app/js/components/Browse.js index 671552529..6458ad22b 100644 --- a/browser/app/js/components/Browse.js +++ b/browser/app/js/components/Browse.js @@ -47,6 +47,7 @@ import * as mime from '../mime' import { minioBrowserPrefix } from '../constants' import CopyToClipboard from 'react-copy-to-clipboard' import storage from 'local-storage-fallback' +import InfiniteScroll from 'react-infinite-scroller'; export default class Browse extends React.Component { componentDidMount() { @@ -110,9 +111,6 @@ export default class Browse extends React.Component { if (!decPathname.endsWith('/')) decPathname += '/' if (decPathname === minioBrowserPrefix + '/') { - dispatch(actions.setCurrentBucket('')) - dispatch(actions.setCurrentPath('')) - dispatch(actions.setObjects([])) return } let obj = utils.pathSlice(decPathname) @@ -140,6 +138,11 @@ export default class Browse extends React.Component { this.props.dispatch(actions.setVisibleBuckets(buckets.filter(bucket => bucket.indexOf(e.target.value) > -1))) } + listObjects() { + const {dispatch} = this.props + dispatch(actions.listObjects()) + } + selectPrefix(e, prefix) { e.preventDefault() const {dispatch, currentPath, web, currentBucket} = this.props @@ -231,7 +234,7 @@ export default class Browse extends React.Component { }) .then(() => { this.hideDeleteConfirmation() - dispatch(actions.selectPrefix(currentPath)) + dispatch(actions.removeObject(deleteConfirmation.object)) }) .catch(e => dispatch(actions.showAlert({ type: 'danger', @@ -296,11 +299,6 @@ export default class Browse extends React.Component { browserHistory.push(`${minioBrowserPrefix}/login`) } - landingPage(e) { - e.preventDefault() - this.props.dispatch(actions.selectBucket(this.props.buckets[0])) - } - fullScreen(e) { e.preventDefault() let el = document.documentElement @@ -365,7 +363,6 @@ export default class Browse extends React.Component { } } - render() { const {total, free} = this.props.storageInfo const {showMakeBucketModal, alert, sortNameOrder, sortSizeOrder, sortDateOrder, showAbout, showBucketPolicy} = this.props @@ -375,7 +372,7 @@ export default class Browse extends React.Component { const {policies, currentBucket, currentPath} = this.props const {deleteConfirmation} = this.props const {shareObject} = this.props - const {web, prefixWritable} = this.props + const {web, prefixWritable, istruncated} = this.props // Don't always show the SettingsModal. This is done here instead of in // SettingsModal.js so as to allow for #componentWillMount to handle @@ -414,10 +411,10 @@ export default class Browse extends React.Component { let freePercent = free * 100 / total if (web.LoggedIn()) { - browserDropdownButton = + browserDropdownButton = } else { loginButton = Login } @@ -481,7 +478,6 @@ export default class Browse extends React.Component { - } return ( @@ -489,8 +485,7 @@ export default class Browse extends React.Component { 'file-explorer': true, 'toggled': sidebarStatus }) }> - @@ -551,10 +546,18 @@ export default class Browse extends React.Component {
- + + + +
+ Loading... +
{ createButton } diff --git a/browser/app/js/components/BrowserDropdown.js b/browser/app/js/components/BrowserDropdown.js index 1aa272551..171e6f3e7 100644 --- a/browser/app/js/components/BrowserDropdown.js +++ b/browser/app/js/components/BrowserDropdown.js @@ -18,7 +18,7 @@ import React from 'react' import connect from 'react-redux/lib/components/connect' import Dropdown from 'react-bootstrap/lib/Dropdown' -let BrowserDropdown = ({fullScreen, showAbout, showSettings, logout}) => { +let BrowserDropdown = ({fullScreenFunc, aboutFunc, settingsFunc, logoutFunc}) => { return (
  • @@ -30,7 +30,7 @@ let BrowserDropdown = ({fullScreen, showAbout, showSettings, logout}) => { Github
  • - Fullscreen + Fullscreen
  • Documentation @@ -39,13 +39,13 @@ let BrowserDropdown = ({fullScreen, showAbout, showSettings, logout}) => { Ask for help
  • - About + About
  • - Settings + Settings
  • - Sign Out + Sign Out
  • diff --git a/browser/app/js/components/Path.js b/browser/app/js/components/Path.js index 6ca85869b..901f094aa 100644 --- a/browser/app/js/components/Path.js +++ b/browser/app/js/components/Path.js @@ -29,7 +29,7 @@ let Path = ({currentBucket, currentPath, selectPrefix}) => { } return ( -

    selectPrefix(e, '') } href="">{ currentBucket }{ path }

    +

    selectPrefix(e, '') } href="">{ currentBucket }{ path }

    ) } diff --git a/browser/app/js/components/SideBar.js b/browser/app/js/components/SideBar.js index ad4aee576..d92bfbceb 100644 --- a/browser/app/js/components/SideBar.js +++ b/browser/app/js/components/SideBar.js @@ -22,7 +22,7 @@ import connect from 'react-redux/lib/components/connect' import logo from '../../img/logo.svg' -let SideBar = ({visibleBuckets, loadBucket, currentBucket, selectBucket, searchBuckets, landingPage, sidebarStatus, clickOutside, showPolicy}) => { +let SideBar = ({visibleBuckets, loadBucket, currentBucket, selectBucket, searchBuckets, sidebarStatus, clickOutside, showPolicy}) => { const list = visibleBuckets.map((bucket, i) => { return
  • - -

    Minio Browser

    + +

    Minio Browser

    diff --git a/browser/app/js/reducers.js b/browser/app/js/reducers.js index 00482e1ff..ca312fbe7 100644 --- a/browser/app/js/reducers.js +++ b/browser/app/js/reducers.js @@ -21,6 +21,7 @@ export default (state = { buckets: [], visibleBuckets: [], objects: [], + istruncated: true, storageInfo: {}, serverInfo: {}, currentBucket: '', @@ -76,7 +77,15 @@ export default (state = { newState.currentBucket = action.currentBucket break case actions.SET_OBJECTS: - newState.objects = action.objects + if (!action.objects.length) { + newState.objects = [] + newState.marker = "" + newState.istruncated = action.istruncated + } else { + newState.objects = [...newState.objects, ...action.objects] + newState.marker = action.marker + newState.istruncated = action.istruncated + } break case actions.SET_CURRENT_PATH: newState.currentPath = action.currentPath @@ -171,6 +180,11 @@ export default (state = { case actions.SET_PREFIX_WRITABLE: newState.prefixWritable = action.prefixWritable break + case actions.REMOVE_OBJECT: + let idx = newState.objects.findIndex(object => object.name === action.object) + if (idx == -1) break + newState.objects = [...newState.objects.slice(0, idx), ...newState.objects.slice(idx + 1)] + break } return newState } diff --git a/browser/package.json b/browser/package.json index 23e8145c6..583d87621 100644 --- a/browser/package.json +++ b/browser/package.json @@ -32,6 +32,7 @@ "copy-webpack-plugin": "^0.3.3", "css-loader": "^0.23.1", "esformatter": "^0.10.0", + "esformatter-jsx": "^7.4.1", "esformatter-jsx-ignore": "^1.0.6", "expect": "^1.20.2", "history": "^1.17.0", @@ -77,6 +78,7 @@ "react-custom-scrollbars": "^2.2.2", "react-dom": "^0.14.6", "react-dropzone": "^3.5.3", + "react-infinite-scroller": "^1.0.6", "react-onclickout": "2.0.4" } } diff --git a/browser/ui-assets.go b/browser/ui-assets.go index fdceb7cbb..773e9288b 100644 --- a/browser/ui-assets.go +++ b/browser/ui-assets.go @@ -4,7 +4,7 @@ // production/favicon.ico // production/firefox.png // production/index.html -// production/index_bundle-2017-01-25T03-10-51Z.js +// production/index_bundle-2017-02-15T22-41-23Z.js // production/loader.css // production/logo.svg // production/safari.png @@ -65,7 +65,7 @@ func productionChromePng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/chrome.png", size: 3726, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/chrome.png", size: 3726, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -82,7 +82,7 @@ func productionFaviconIco() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/favicon.ico", size: 1340, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/favicon.ico", size: 1340, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -99,7 +99,7 @@ func productionFirefoxPng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/firefox.png", size: 4795, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/firefox.png", size: 4795, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -156,8 +156,8 @@ var _productionIndexHTML = []byte(`
    - - + + `) @@ -172,21 +172,21 @@ func productionIndexHTML() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/index.html", size: 1996, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/index.html", size: 1996, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _productionIndex_bundle20170125t031051zJs = []byte(`!function(A){function M(I){if(t[I])return t[I].exports;var g=t[I]={exports:{},id:I,loaded:!1};return A[I].call(g.exports,g,g.exports,M),g.loaded=!0,g.exports}var t={};return M.m=A,M.c=t,M.p="",M(0)}([function(A,M,t){A.exports=t(240)},function(A,M,t){"use strict";A.exports=t(439)},function(A,M,t){"use strict";function I(A,M,t,I,g,e,i,T){if(!A){var E;if(void 0===M)E=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var N=[t,I,g,e,i,T],o=0;E=new Error(M.replace(/%s/g,function(){return N[o++]})),E.name="Invariant Violation"}throw E.framesToPop=1,E}}A.exports=I},function(A,M,t){"use strict";var I=t(20),g=I;A.exports=g},function(A,M){"use strict";function t(A,M){if(null==A)throw new TypeError("Object.assign target cannot be null or undefined");for(var t=Object(A),I=Object.prototype.hasOwnProperty,g=1;g2?t-2:0),g=2;g1){for(var c=Array(C),D=0;D1){for(var a=Array(D),B=0;B3&&void 0!==arguments[3]?arguments[3]:{},N=Boolean(A),C=A||w,D=void 0;D="function"==typeof M?M:M?(0,Q.default)(M):L;var B=t||l,r=I.pure,s=void 0===r||r,x=I.withRef,y=void 0!==x&&x,h=s&&B!==l,S=d++;return function(A){function M(A,M,t){var I=B(A,M,t);return I}var t="Connect("+T(A)+")",I=function(I){function T(A,M){g(this,T);var i=e(this,I.call(this,A,M));i.version=S,i.store=A.store||M.store,(0,u.default)(i.store,'Could not find "store" in either the context or '+('props of "'+t+'". ')+"Either wrap the root component in a , "+('or explicitly pass "store" as a prop to "'+t+'".'));var E=i.store.getState();return i.state={storeState:E},i.clearCache(),i}return i(T,I),T.prototype.shouldComponentUpdate=function(){return!s||this.haveOwnPropsChanged||this.hasStoreStateChanged},T.prototype.computeStateProps=function(A,M){if(!this.finalMapStateToProps)return this.configureFinalMapState(A,M);var t=A.getState(),I=this.doStatePropsDependOnOwnProps?this.finalMapStateToProps(t,M):this.finalMapStateToProps(t);return I},T.prototype.configureFinalMapState=function(A,M){var t=C(A.getState(),M),I="function"==typeof t;return this.finalMapStateToProps=I?t:C,this.doStatePropsDependOnOwnProps=1!==this.finalMapStateToProps.length,I?this.computeStateProps(A,M):t},T.prototype.computeDispatchProps=function(A,M){if(!this.finalMapDispatchToProps)return this.configureFinalMapDispatch(A,M);var t=A.dispatch,I=this.doDispatchPropsDependOnOwnProps?this.finalMapDispatchToProps(t,M):this.finalMapDispatchToProps(t);return I},T.prototype.configureFinalMapDispatch=function(A,M){var t=D(A.dispatch,M),I="function"==typeof t;return this.finalMapDispatchToProps=I?t:D,this.doDispatchPropsDependOnOwnProps=1!==this.finalMapDispatchToProps.length,I?this.computeDispatchProps(A,M):t},T.prototype.updateStatePropsIfNeeded=function(){var A=this.computeStateProps(this.store,this.props);return(!this.stateProps||!(0,a.default)(A,this.stateProps))&&(this.stateProps=A,!0)},T.prototype.updateDispatchPropsIfNeeded=function(){var A=this.computeDispatchProps(this.store,this.props);return(!this.dispatchProps||!(0,a.default)(A,this.dispatchProps))&&(this.dispatchProps=A,!0)},T.prototype.updateMergedPropsIfNeeded=function(){var A=M(this.stateProps,this.dispatchProps,this.props);return!(this.mergedProps&&h&&(0,a.default)(A,this.mergedProps))&&(this.mergedProps=A,!0)},T.prototype.isSubscribed=function(){return"function"==typeof this.unsubscribe},T.prototype.trySubscribe=function(){N&&!this.unsubscribe&&(this.unsubscribe=this.store.subscribe(this.handleChange.bind(this)),this.handleChange())},T.prototype.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null)},T.prototype.componentDidMount=function(){this.trySubscribe()},T.prototype.componentWillReceiveProps=function(A){s&&(0,a.default)(A,this.props)||(this.haveOwnPropsChanged=!0)},T.prototype.componentWillUnmount=function(){this.tryUnsubscribe(),this.clearCache()},T.prototype.clearCache=function(){this.dispatchProps=null,this.stateProps=null,this.mergedProps=null,this.haveOwnPropsChanged=!0,this.hasStoreStateChanged=!0,this.haveStatePropsBeenPrecalculated=!1,this.statePropsPrecalculationError=null,this.renderedElement=null,this.finalMapDispatchToProps=null,this.finalMapStateToProps=null},T.prototype.handleChange=function(){if(this.unsubscribe){var A=this.store.getState(),M=this.state.storeState;if(!s||M!==A){if(s&&!this.doStatePropsDependOnOwnProps){var t=E(this.updateStatePropsIfNeeded,this);if(!t)return;t===Y&&(this.statePropsPrecalculationError=Y.value),this.haveStatePropsBeenPrecalculated=!0}this.hasStoreStateChanged=!0,this.setState({storeState:A})}}},T.prototype.getWrappedInstance=function(){return(0,u.default)(y,"To access the wrapped instance, you need to specify { withRef: true } as the fourth argument of the connect() call."),this.refs.wrappedInstance},T.prototype.render=function(){var M=this.haveOwnPropsChanged,t=this.hasStoreStateChanged,I=this.haveStatePropsBeenPrecalculated,g=this.statePropsPrecalculationError,e=this.renderedElement;if(this.haveOwnPropsChanged=!1,this.hasStoreStateChanged=!1,this.haveStatePropsBeenPrecalculated=!1,this.statePropsPrecalculationError=null,g)throw g;var i=!0,T=!0;s&&e&&(i=t||M&&this.doStatePropsDependOnOwnProps,T=M&&this.doDispatchPropsDependOnOwnProps);var E=!1,N=!1;I?E=!0:i&&(E=this.updateStatePropsIfNeeded()),T&&(N=this.updateDispatchPropsIfNeeded());var C=!0;return C=!!(E||N||M)&&this.updateMergedPropsIfNeeded(),!C&&e?e:(y?this.renderedElement=(0,n.createElement)(A,o({},this.mergedProps,{ref:"wrappedInstance"})):this.renderedElement=(0,n.createElement)(A,this.mergedProps),this.renderedElement)},T}(n.Component);return I.displayName=t,I.WrappedComponent=A,I.contextTypes={store:c.default},I.propTypes={store:c.default},(0,j.default)(I,A)}}M.__esModule=!0;var o=Object.assign||function(A){for(var M=1;M should not have a "'+M+'" prop')}M.__esModule=!0,M.routes=M.route=M.components=M.component=M.history=void 0,M.falsy=I;var g=t(1),e=g.PropTypes.func,i=g.PropTypes.object,T=g.PropTypes.arrayOf,E=g.PropTypes.oneOfType,N=g.PropTypes.element,o=g.PropTypes.shape,n=g.PropTypes.string,C=(M.history=o({listen:e.isRequired,push:e.isRequired,replace:e.isRequired,go:e.isRequired,goBack:e.isRequired,goForward:e.isRequired}),M.component=E([e,n])),c=(M.components=E([C,i]),M.route=E([i,N]));M.routes=E([c,T(c)])},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A){var M=A.match(/^https?:\/\/[^\/]*/); -return null==M?A:A.substring(M[0].length)}function e(A){var M=g(A),t="",I="",e=M.indexOf("#");e!==-1&&(I=M.substring(e),M=M.substring(0,e));var i=M.indexOf("?");return i!==-1&&(t=M.substring(i),M=M.substring(0,i)),""===M&&(M="/"),{pathname:M,search:t,hash:I}}M.__esModule=!0,M.extractPath=g,M.parsePath=e;var i=t(23);I(i)},function(A,M,t){"use strict";function I(){g.attachRefs(this,this._currentElement)}var g=t(458),e={mountComponent:function(A,M,t,g){var e=A.mountComponent(M,t,g);return A._currentElement&&null!=A._currentElement.ref&&t.getReactMountReady().enqueue(I,A),e},unmountComponent:function(A){g.detachRefs(A,A._currentElement),A.unmountComponent()},receiveComponent:function(A,M,t,e){var i=A._currentElement;if(M!==i||e!==A._context){var T=g.shouldUpdateRefs(i,M);T&&g.detachRefs(A,i),A.receiveComponent(M,t,e),T&&A._currentElement&&null!=A._currentElement.ref&&t.getReactMountReady().enqueue(I,A)}},performUpdateIfNecessary:function(A,M){A.performUpdateIfNecessary(M)}};A.exports=e},function(A,M,t){"use strict";function I(A,M,t,I){this.dispatchConfig=A,this.dispatchMarker=M,this.nativeEvent=t;var g=this.constructor.Interface;for(var e in g)if(g.hasOwnProperty(e)){var T=g[e];T?this[e]=T(t):"target"===e?this.target=I:this[e]=t[e]}var E=null!=t.defaultPrevented?t.defaultPrevented:t.returnValue===!1;E?this.isDefaultPrevented=i.thatReturnsTrue:this.isDefaultPrevented=i.thatReturnsFalse,this.isPropagationStopped=i.thatReturnsFalse}var g=t(31),e=t(4),i=t(20),T=(t(3),{type:null,target:null,currentTarget:i.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(A){return A.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null});e(I.prototype,{preventDefault:function(){this.defaultPrevented=!0;var A=this.nativeEvent;A&&(A.preventDefault?A.preventDefault():A.returnValue=!1,this.isDefaultPrevented=i.thatReturnsTrue)},stopPropagation:function(){var A=this.nativeEvent;A&&(A.stopPropagation?A.stopPropagation():A.cancelBubble=!0,this.isPropagationStopped=i.thatReturnsTrue)},persist:function(){this.isPersistent=i.thatReturnsTrue},isPersistent:i.thatReturnsFalse,destructor:function(){var A=this.constructor.Interface;for(var M in A)this[M]=null;this.dispatchConfig=null,this.dispatchMarker=null,this.nativeEvent=null}}),I.Interface=T,I.augmentClass=function(A,M){var t=this,I=Object.create(t.prototype);e(I,A.prototype),A.prototype=I,A.prototype.constructor=A,A.Interface=e({},t.Interface,M),A.augmentClass=t.augmentClass,g.addPoolingTo(A,g.fourArgumentPooler)},g.addPoolingTo(I,g.fourArgumentPooler),A.exports=I},function(A,M){"use strict";M.default=function(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t},M.__esModule=!0},function(A,M){"use strict";function t(A){return A&&A.ownerDocument||document}M.__esModule=!0,M.default=t,A.exports=M.default},function(A,M,t){"use strict";var I=t(32),g=function(){var A=I&&document.documentElement;return A&&A.contains?function(A,M){return A.contains(M)}:A&&A.compareDocumentPosition?function(A,M){return A===M||!!(16&A.compareDocumentPosition(M))}:function(A,M){if(M)do if(M===A)return!0;while(M=M.parentNode);return!1}}();A.exports=g},function(A,M){function t(A){return"number"==typeof A&&A>-1&&A%1==0&&A<=I}var I=9007199254740991;A.exports=t},function(A,M,t){(function(A){!function(M,t){A.exports=t()}(this,function(){"use strict";function M(){return aI.apply(null,arguments)}function t(A){aI=A}function I(A){return A instanceof Array||"[object Array]"===Object.prototype.toString.call(A)}function g(A){return null!=A&&"[object Object]"===Object.prototype.toString.call(A)}function e(A){var M;for(M in A)return!1;return!0}function i(A){return"number"==typeof A||"[object Number]"===Object.prototype.toString.call(A)}function T(A){return A instanceof Date||"[object Date]"===Object.prototype.toString.call(A)}function E(A,M){var t,I=[];for(t=0;t0)for(t in rI)I=rI[t],g=M[I],B(g)||(A[I]=g);return A}function r(A){Q(this,A),this._d=new Date(null!=A._d?A._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),sI===!1&&(sI=!0,M.updateOffset(this),sI=!1)}function s(A){return A instanceof r||null!=A&&null!=A._isAMomentObject}function x(A){return A<0?Math.ceil(A)||0:Math.floor(A)}function j(A){var M=+A,t=0;return 0!==M&&isFinite(M)&&(t=x(M)),t}function y(A,M,t){var I,g=Math.min(A.length,M.length),e=Math.abs(A.length-M.length),i=0;for(I=0;I0?"future":"past"];return l(t)?t(M):t.replace(/%s/i,M)}function F(A,M){var t=A.toLowerCase();SI[t]=SI[t+"s"]=SI[M]=A}function f(A){return"string"==typeof A?SI[A]||SI[A.toLowerCase()]:void 0}function k(A){var M,t,I={};for(t in A)N(A,t)&&(M=f(t),M&&(I[M]=A[t]));return I}function R(A,M){zI[A]=M}function J(A){var M=[];for(var t in A)M.push({unit:t,priority:zI[t]});return M.sort(function(A,M){return A.priority-M.priority}),M}function G(A,t){return function(I){return null!=I?(b(this,A,I),M.updateOffset(this,t),this):H(this,A)}}function H(A,M){return A.isValid()?A._d["get"+(A._isUTC?"UTC":"")+M]():NaN}function b(A,M,t){A.isValid()&&A._d["set"+(A._isUTC?"UTC":"")+M](t)}function X(A){return A=f(A),l(this[A])?this[A]():this}function v(A,M){if("object"==typeof A){A=k(A);for(var t=J(A),I=0;I=0;return(e?t?"+":"":"-")+Math.pow(10,Math.max(0,g)).toString().substr(1)+I}function V(A,M,t,I){var g=I;"string"==typeof I&&(g=function(){return this[I]()}),A&&(mI[A]=g),M&&(mI[M[0]]=function(){return W(g.apply(this,arguments),M[1],M[2])}),t&&(mI[t]=function(){return this.localeData().ordinal(g.apply(this,arguments),A)})}function P(A){return A.match(/\[[\s\S]/)?A.replace(/^\[|\]$/g,""):A.replace(/\\/g,"")}function Z(A){var M,t,I=A.match(UI);for(M=0,t=I.length;M=0&&pI.test(A);)A=A.replace(pI,t),pI.lastIndex=0,I-=1;return A}function _(A,M,t){$I[A]=l(M)?M:function(A,I){return A&&t?t:M}}function $(A,M){return N($I,A)?$I[A](M._strict,M._locale):new RegExp(AA(A))}function AA(A){return MA(A.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(A,M,t,I,g){return M||t||I||g}))}function MA(A){return A.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function tA(A,M){var t,I=M;for("string"==typeof A&&(A=[A]),i(M)&&(I=function(A,t){t[M]=j(A)}),t=0;t=0&&isFinite(T.getFullYear())&&T.setFullYear(A),T}function xA(A){var M=new Date(Date.UTC.apply(null,arguments));return A<100&&A>=0&&isFinite(M.getUTCFullYear())&&M.setUTCFullYear(A),M}function jA(A,M,t){var I=7+M-t,g=(7+xA(A,0,I).getUTCDay()-M)%7;return-g+I-1}function yA(A,M,t,I,g){var e,i,T=(7+t-I)%7,E=jA(A,I,g),N=1+7*(M-1)+T+E;return N<=0?(e=A-1,i=BA(e)+N):N>BA(A)?(e=A+1,i=N-BA(A)):(e=A,i=N),{year:e,dayOfYear:i}}function uA(A,M,t){var I,g,e=jA(A.year(),M,t),i=Math.floor((A.dayOfYear()-e-1)/7)+1;return i<1?(g=A.year()-1,I=i+wA(g,M,t)):i>wA(A.year(),M,t)?(I=i-wA(A.year(),M,t),g=A.year()+1):(g=A.year(),I=i),{week:I,year:g}}function wA(A,M,t){var I=jA(A,M,t),g=jA(A+1,M,t);return(BA(A)-I+g)/7}function LA(A){return uA(A,this._week.dow,this._week.doy).week}function lA(){return this._week.dow}function YA(){return this._week.doy}function dA(A){var M=this.localeData().week(this);return null==A?M:this.add(7*(A-M),"d")}function hA(A){var M=uA(this,1,4).week;return null==A?M:this.add(7*(A-M),"d")}function SA(A,M){return"string"!=typeof A?A:isNaN(A)?(A=M.weekdaysParse(A),"number"==typeof A?A:null):parseInt(A,10)}function zA(A,M){return"string"==typeof A?M.weekdaysParse(A)%7||7:isNaN(A)?null:A}function UA(A,M){return A?I(this._weekdays)?this._weekdays[A.day()]:this._weekdays[this._weekdays.isFormat.test(M)?"format":"standalone"][A.day()]:this._weekdays}function pA(A){return A?this._weekdaysShort[A.day()]:this._weekdaysShort}function OA(A){return A?this._weekdaysMin[A.day()]:this._weekdaysMin}function mA(A,M,t){var I,g,e,i=A.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],I=0;I<7;++I)e=n([2e3,1]).day(I),this._minWeekdaysParse[I]=this.weekdaysMin(e,"").toLocaleLowerCase(),this._shortWeekdaysParse[I]=this.weekdaysShort(e,"").toLocaleLowerCase(),this._weekdaysParse[I]=this.weekdays(e,"").toLocaleLowerCase();return t?"dddd"===M?(g=og.call(this._weekdaysParse,i),g!==-1?g:null):"ddd"===M?(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:null):(g=og.call(this._minWeekdaysParse,i),g!==-1?g:null):"dddd"===M?(g=og.call(this._weekdaysParse,i),g!==-1?g:(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:(g=og.call(this._minWeekdaysParse,i),g!==-1?g:null))):"ddd"===M?(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:(g=og.call(this._weekdaysParse,i),g!==-1?g:(g=og.call(this._minWeekdaysParse,i),g!==-1?g:null))):(g=og.call(this._minWeekdaysParse,i),g!==-1?g:(g=og.call(this._weekdaysParse,i),g!==-1?g:(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:null)))}function FA(A,M,t){var I,g,e;if(this._weekdaysParseExact)return mA.call(this,A,M,t);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),I=0;I<7;I++){if(g=n([2e3,1]).day(I),t&&!this._fullWeekdaysParse[I]&&(this._fullWeekdaysParse[I]=new RegExp("^"+this.weekdays(g,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[I]=new RegExp("^"+this.weekdaysShort(g,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[I]=new RegExp("^"+this.weekdaysMin(g,"").replace(".",".?")+"$","i")),this._weekdaysParse[I]||(e="^"+this.weekdays(g,"")+"|^"+this.weekdaysShort(g,"")+"|^"+this.weekdaysMin(g,""),this._weekdaysParse[I]=new RegExp(e.replace(".",""),"i")),t&&"dddd"===M&&this._fullWeekdaysParse[I].test(A))return I;if(t&&"ddd"===M&&this._shortWeekdaysParse[I].test(A))return I;if(t&&"dd"===M&&this._minWeekdaysParse[I].test(A))return I;if(!t&&this._weekdaysParse[I].test(A))return I}}function fA(A){if(!this.isValid())return null!=A?this:NaN;var M=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=A?(A=SA(A,this.localeData()),this.add(A-M,"d")):M}function kA(A){if(!this.isValid())return null!=A?this:NaN;var M=(this.day()+7-this.localeData()._week.dow)%7;return null==A?M:this.add(A-M,"d")}function RA(A){if(!this.isValid())return null!=A?this:NaN;if(null!=A){var M=zA(A,this.localeData());return this.day(this.day()%7?M:M-7)}return this.day()||7}function JA(A){return this._weekdaysParseExact?(N(this,"_weekdaysRegex")||bA.call(this),A?this._weekdaysStrictRegex:this._weekdaysRegex):(N(this,"_weekdaysRegex")||(this._weekdaysRegex=jg),this._weekdaysStrictRegex&&A?this._weekdaysStrictRegex:this._weekdaysRegex)}function GA(A){return this._weekdaysParseExact?(N(this,"_weekdaysRegex")||bA.call(this),A?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(N(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=yg),this._weekdaysShortStrictRegex&&A?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function HA(A){return this._weekdaysParseExact?(N(this,"_weekdaysRegex")||bA.call(this),A?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(N(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=ug),this._weekdaysMinStrictRegex&&A?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function bA(){function A(A,M){return M.length-A.length}var M,t,I,g,e,i=[],T=[],E=[],N=[];for(M=0;M<7;M++)t=n([2e3,1]).day(M),I=this.weekdaysMin(t,""),g=this.weekdaysShort(t,""),e=this.weekdays(t,""),i.push(I),T.push(g),E.push(e),N.push(I),N.push(g),N.push(e);for(i.sort(A),T.sort(A),E.sort(A),N.sort(A),M=0;M<7;M++)T[M]=MA(T[M]),E[M]=MA(E[M]),N[M]=MA(N[M]);this._weekdaysRegex=new RegExp("^("+N.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+E.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+T.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+i.join("|")+")","i")}function XA(){return this.hours()%12||12}function vA(){return this.hours()||24}function WA(A,M){V(A,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),M)})}function VA(A,M){return M._meridiemParse}function PA(A){return"p"===(A+"").toLowerCase().charAt(0)}function ZA(A,M,t){return A>11?t?"pm":"PM":t?"am":"AM"}function KA(A){return A?A.toLowerCase().replace("_","-"):A}function qA(A){for(var M,t,I,g,e=0;e0;){if(I=_A(g.slice(0,M).join("-")))return I;if(t&&t.length>=M&&y(g,t,!0)>=M-1)break;M--}e++}return null}function _A(M){var t=null;if(!dg[M]&&"undefined"!=typeof A&&A&&A.exports)try{t=wg._abbr,!function(){var A=new Error('Cannot find module "./locale"');throw A.code="MODULE_NOT_FOUND",A}(),$A(t)}catch(A){}return dg[M]}function $A(A,M){var t;return A&&(t=B(M)?tM(A):AM(A,M),t&&(wg=t)),wg._abbr}function AM(A,M){if(null!==M){var t=Yg;if(M.abbr=A,null!=dg[A])L("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),t=dg[A]._config;else if(null!=M.parentLocale){if(null==dg[M.parentLocale])return hg[M.parentLocale]||(hg[M.parentLocale]=[]),hg[M.parentLocale].push({name:A,config:M}),null;t=dg[M.parentLocale]._config}return dg[A]=new h(d(t,M)),hg[A]&&hg[A].forEach(function(A){AM(A.name,A.config)}),$A(A),dg[A]}return delete dg[A],null}function MM(A,M){if(null!=M){var t,I=Yg;null!=dg[A]&&(I=dg[A]._config),M=d(I,M),t=new h(M),t.parentLocale=dg[A],dg[A]=t,$A(A)}else null!=dg[A]&&(null!=dg[A].parentLocale?dg[A]=dg[A].parentLocale:null!=dg[A]&&delete dg[A]);return dg[A]}function tM(A){var M;if(A&&A._locale&&A._locale._abbr&&(A=A._locale._abbr),!A)return wg;if(!I(A)){if(M=_A(A))return M;A=[A]}return qA(A)}function IM(){return uI(dg)}function gM(A){var M,t=A._a;return t&&c(A).overflow===-2&&(M=t[tg]<0||t[tg]>11?tg:t[Ig]<1||t[Ig]>eA(t[Mg],t[tg])?Ig:t[gg]<0||t[gg]>24||24===t[gg]&&(0!==t[eg]||0!==t[ig]||0!==t[Tg])?gg:t[eg]<0||t[eg]>59?eg:t[ig]<0||t[ig]>59?ig:t[Tg]<0||t[Tg]>999?Tg:-1,c(A)._overflowDayOfYear&&(MIg)&&(M=Ig),c(A)._overflowWeeks&&M===-1&&(M=Eg),c(A)._overflowWeekday&&M===-1&&(M=Ng),c(A).overflow=M),A}function eM(A){var M,t,I,g,e,i,T=A._i,E=Sg.exec(T)||zg.exec(T);if(E){for(c(A).iso=!0,M=0,t=pg.length;MBA(g)&&(c(A)._overflowDayOfYear=!0),t=xA(g,0,A._dayOfYear),A._a[tg]=t.getUTCMonth(),A._a[Ig]=t.getUTCDate()),M=0;M<3&&null==A._a[M];++M)A._a[M]=e[M]=I[M];for(;M<7;M++)A._a[M]=e[M]=null==A._a[M]?2===M?1:0:A._a[M];24===A._a[gg]&&0===A._a[eg]&&0===A._a[ig]&&0===A._a[Tg]&&(A._nextDay=!0,A._a[gg]=0),A._d=(A._useUTC?xA:sA).apply(null,e),null!=A._tzm&&A._d.setUTCMinutes(A._d.getUTCMinutes()-A._tzm),A._nextDay&&(A._a[gg]=24)}}function oM(A){var M,t,I,g,e,i,T,E;if(M=A._w,null!=M.GG||null!=M.W||null!=M.E)e=1,i=4,t=TM(M.GG,A._a[Mg],uA(sM(),1,4).year),I=TM(M.W,1),g=TM(M.E,1),(g<1||g>7)&&(E=!0);else{e=A._locale._week.dow,i=A._locale._week.doy;var N=uA(sM(),e,i);t=TM(M.gg,A._a[Mg],N.year),I=TM(M.w,N.week),null!=M.d?(g=M.d,(g<0||g>6)&&(E=!0)):null!=M.e?(g=M.e+e,(M.e<0||M.e>6)&&(E=!0)):g=e}I<1||I>wA(t,e,i)?c(A)._overflowWeeks=!0:null!=E?c(A)._overflowWeekday=!0:(T=yA(t,I,g,e,i),A._a[Mg]=T.year,A._dayOfYear=T.dayOfYear)}function nM(A){if(A._f===M.ISO_8601)return void eM(A);A._a=[],c(A).empty=!0;var t,I,g,e,i,T=""+A._i,E=T.length,N=0;for(g=q(A._f,A._locale).match(UI)||[],t=0;t0&&c(A).unusedInput.push(i),T=T.slice(T.indexOf(I)+I.length),N+=I.length),mI[e]?(I?c(A).empty=!1:c(A).unusedTokens.push(e),gA(e,I,A)):A._strict&&!I&&c(A).unusedTokens.push(e);c(A).charsLeftOver=E-N,T.length>0&&c(A).unusedInput.push(T),A._a[gg]<=12&&c(A).bigHour===!0&&A._a[gg]>0&&(c(A).bigHour=void 0),c(A).parsedDateParts=A._a.slice(0),c(A).meridiem=A._meridiem,A._a[gg]=CM(A._locale,A._a[gg],A._meridiem),NM(A),gM(A)}function CM(A,M,t){var I;return null==t?M:null!=A.meridiemHour?A.meridiemHour(M,t):null!=A.isPM?(I=A.isPM(t),I&&M<12&&(M+=12),I||12!==M||(M=0),M):M}function cM(A){var M,t,I,g,e;if(0===A._f.length)return c(A).invalidFormat=!0,void(A._d=new Date(NaN));for(g=0;gthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function fM(){if(!B(this._isDSTShifted))return this._isDSTShifted;var A={};if(Q(A,this),A=BM(A),A._a){var M=A._isUTC?n(A._a):sM(A._a);this._isDSTShifted=this.isValid()&&y(A._a,M.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function kM(){return!!this.isValid()&&!this._isUTC}function RM(){return!!this.isValid()&&this._isUTC}function JM(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function GM(A,M){var t,I,g,e=A,T=null;return wM(A)?e={ms:A._milliseconds,d:A._days,M:A._months}:i(A)?(e={},M?e[M]=A:e.milliseconds=A):(T=Jg.exec(A))?(t="-"===T[1]?-1:1,e={y:0,d:j(T[Ig])*t,h:j(T[gg])*t,m:j(T[eg])*t,s:j(T[ig])*t,ms:j(LM(1e3*T[Tg]))*t}):(T=Gg.exec(A))?(t="-"===T[1]?-1:1,e={y:HM(T[2],t),M:HM(T[3],t),w:HM(T[4],t),d:HM(T[5],t),h:HM(T[6],t),m:HM(T[7],t),s:HM(T[8],t)}):null==e?e={}:"object"==typeof e&&("from"in e||"to"in e)&&(g=XM(sM(e.from),sM(e.to)),e={},e.ms=g.milliseconds,e.M=g.months),I=new uM(e),wM(A)&&N(A,"_locale")&&(I._locale=A._locale),I}function HM(A,M){var t=A&&parseFloat(A.replace(",","."));return(isNaN(t)?0:t)*M}function bM(A,M){var t={milliseconds:0,months:0};return t.months=M.month()-A.month()+12*(M.year()-A.year()),A.clone().add(t.months,"M").isAfter(M)&&--t.months,t.milliseconds=+M-+A.clone().add(t.months,"M"),t}function XM(A,M){var t;return A.isValid()&&M.isValid()?(M=dM(M,A),A.isBefore(M)?t=bM(A,M):(t=bM(M,A),t.milliseconds=-t.milliseconds,t.months=-t.months),t):{milliseconds:0,months:0}}function vM(A,M){return function(t,I){var g,e;return null===I||isNaN(+I)||(L(M,"moment()."+M+"(period, number) is deprecated. Please use moment()."+M+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),e=t,t=I,I=e),t="string"==typeof t?+t:t,g=GM(t,I),WM(this,g,A),this}}function WM(A,t,I,g){var e=t._milliseconds,i=LM(t._days),T=LM(t._months);A.isValid()&&(g=null==g||g,e&&A._d.setTime(A._d.valueOf()+e*I),i&&b(A,"Date",H(A,"Date")+i*I),T&&oA(A,H(A,"Month")+T*I),g&&M.updateOffset(A,i||T))}function VM(A,M){var t=A.diff(M,"days",!0);return t<-6?"sameElse":t<-1?"lastWeek":t<0?"lastDay":t<1?"sameDay":t<2?"nextDay":t<7?"nextWeek":"sameElse"}function PM(A,t){var I=A||sM(),g=dM(I,this).startOf("day"),e=M.calendarFormat(this,g)||"sameElse",i=t&&(l(t[e])?t[e].call(this,I):t[e]);return this.format(i||this.localeData().calendar(e,this,sM(I)))}function ZM(){return new r(this)}function KM(A,M){var t=s(A)?A:sM(A);return!(!this.isValid()||!t.isValid())&&(M=f(B(M)?"millisecond":M),"millisecond"===M?this.valueOf()>t.valueOf():t.valueOf()e&&(M=e),Ut.call(this,A,M,t,I,g))}function Ut(A,M,t,I,g){var e=yA(A,M,t,I,g),i=xA(e.year,0,e.dayOfYear);return this.year(i.getUTCFullYear()),this.month(i.getUTCMonth()),this.date(i.getUTCDate()),this}function pt(A){return null==A?Math.ceil((this.month()+1)/3):this.month(3*(A-1)+this.month()%3)}function Ot(A){var M=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==A?M:this.add(A-M,"d")}function mt(A,M){M[Tg]=j(1e3*("0."+A))}function Ft(){return this._isUTC?"UTC":""}function ft(){return this._isUTC?"Coordinated Universal Time":""}function kt(A){return sM(1e3*A)}function Rt(){return sM.apply(null,arguments).parseZone()}function Jt(A){return A}function Gt(A,M,t,I){var g=tM(),e=n().set(I,M);return g[t](e,A)}function Ht(A,M,t){if(i(A)&&(M=A,A=void 0),A=A||"",null!=M)return Gt(A,M,t,"month");var I,g=[];for(I=0;I<12;I++)g[I]=Gt(A,I,t,"month");return g}function bt(A,M,t,I){"boolean"==typeof A?(i(M)&&(t=M,M=void 0),M=M||""):(M=A,t=M,A=!1,i(M)&&(t=M,M=void 0),M=M||"");var g=tM(),e=A?g._week.dow:0;if(null!=t)return Gt(M,(t+e)%7,I,"day");var T,E=[];for(T=0;T<7;T++)E[T]=Gt(M,(T+e)%7,I,"day");return E}function Xt(A,M){return Ht(A,M,"months")}function vt(A,M){return Ht(A,M,"monthsShort")}function Wt(A,M,t){return bt(A,M,t,"weekdays")}function Vt(A,M,t){return bt(A,M,t,"weekdaysShort")}function Pt(A,M,t){return bt(A,M,t,"weekdaysMin")}function Zt(){var A=this._data;return this._milliseconds=_g(this._milliseconds),this._days=_g(this._days),this._months=_g(this._months),A.milliseconds=_g(A.milliseconds),A.seconds=_g(A.seconds),A.minutes=_g(A.minutes),A.hours=_g(A.hours),A.months=_g(A.months),A.years=_g(A.years),this}function Kt(A,M,t,I){var g=GM(M,t);return A._milliseconds+=I*g._milliseconds,A._days+=I*g._days,A._months+=I*g._months,A._bubble()}function qt(A,M){return Kt(this,A,M,1)}function _t(A,M){return Kt(this,A,M,-1)}function $t(A){return A<0?Math.floor(A):Math.ceil(A)}function AI(){var A,M,t,I,g,e=this._milliseconds,i=this._days,T=this._months,E=this._data;return e>=0&&i>=0&&T>=0||e<=0&&i<=0&&T<=0||(e+=864e5*$t(tI(T)+i),i=0,T=0),E.milliseconds=e%1e3,A=x(e/1e3),E.seconds=A%60,M=x(A/60),E.minutes=M%60,t=x(M/60),E.hours=t%24,i+=x(t/24),g=x(MI(i)),T+=g,i-=$t(tI(g)),I=x(T/12),T%=12,E.days=i,E.months=T,E.years=I,this}function MI(A){return 4800*A/146097}function tI(A){return 146097*A/4800}function II(A){var M,t,I=this._milliseconds;if(A=f(A),"month"===A||"year"===A)return M=this._days+I/864e5,t=this._months+MI(M),"month"===A?t:t/12;switch(M=this._days+Math.round(tI(this._months)),A){case"week":return M/7+I/6048e5;case"day":return M+I/864e5;case"hour":return 24*M+I/36e5;case"minute":return 1440*M+I/6e4;case"second":return 86400*M+I/1e3;case"millisecond":return Math.floor(864e5*M)+I;default:throw new Error("Unknown unit "+A)}}function gI(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*j(this._months/12)}function eI(A){return function(){return this.as(A)}}function iI(A){return A=f(A),this[A+"s"]()}function TI(A){return function(){return this._data[A]}}function EI(){return x(this.days()/7)}function NI(A,M,t,I,g){return g.relativeTime(M||1,!!t,A,I)}function oI(A,M,t){var I=GM(A).abs(),g=De(I.as("s")),e=De(I.as("m")),i=De(I.as("h")),T=De(I.as("d")),E=De(I.as("M")),N=De(I.as("y")),o=g0,o[4]=t,NI.apply(null,o)}function nI(A){return void 0===A?De:"function"==typeof A&&(De=A,!0)}function CI(A,M){return void 0!==ae[A]&&(void 0===M?ae[A]:(ae[A]=M,!0))}function cI(A){var M=this.localeData(),t=oI(this,!A,M);return A&&(t=M.pastFuture(+this,t)),M.postformat(t)}function DI(){var A,M,t,I=Be(this._milliseconds)/1e3,g=Be(this._days),e=Be(this._months);A=x(I/60),M=x(A/60),I%=60,A%=60,t=x(e/12),e%=12;var i=t,T=e,E=g,N=M,o=A,n=I,C=this.asSeconds();return C?(C<0?"-":"")+"P"+(i?i+"Y":"")+(T?T+"M":"")+(E?E+"D":"")+(N||o||n?"T":"")+(N?N+"H":"")+(o?o+"M":"")+(n?n+"S":""):"P0D"}var aI,BI;BI=Array.prototype.some?Array.prototype.some:function(A){for(var M=Object(this),t=M.length>>>0,I=0;I68?1900:2e3)};var Bg=G("FullYear",!0);V("w",["ww",2],"wo","week"),V("W",["WW",2],"Wo","isoWeek"),F("week","w"),F("isoWeek","W"),R("week",5),R("isoWeek",5),_("w",GI),_("ww",GI,fI),_("W",GI),_("WW",GI,fI),IA(["w","ww","W","WW"],function(A,M,t,I){M[I.substr(0,1)]=j(A)});var Qg={dow:0,doy:6};V("d",0,"do","day"),V("dd",0,0,function(A){return this.localeData().weekdaysMin(this,A)}),V("ddd",0,0,function(A){return this.localeData().weekdaysShort(this,A)}),V("dddd",0,0,function(A){return this.localeData().weekdays(this,A)}),V("e",0,0,"weekday"),V("E",0,0,"isoWeekday"),F("day","d"),F("weekday","e"),F("isoWeekday","E"),R("day",11),R("weekday",11),R("isoWeekday",11),_("d",GI),_("e",GI),_("E",GI),_("dd",function(A,M){return M.weekdaysMinRegex(A)}),_("ddd",function(A,M){return M.weekdaysShortRegex(A)}),_("dddd",function(A,M){return M.weekdaysRegex(A)}),IA(["dd","ddd","dddd"],function(A,M,t,I){var g=t._locale.weekdaysParse(A,I,t._strict);null!=g?M.d=g:c(t).invalidWeekday=A}),IA(["d","e","E"],function(A,M,t,I){M[I]=j(A)});var rg="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),sg="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),xg="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),jg=_I,yg=_I,ug=_I;V("H",["HH",2],0,"hour"),V("h",["hh",2],0,XA),V("k",["kk",2],0,vA),V("hmm",0,0,function(){return""+XA.apply(this)+W(this.minutes(),2)}),V("hmmss",0,0,function(){return""+XA.apply(this)+W(this.minutes(),2)+W(this.seconds(),2)}),V("Hmm",0,0,function(){return""+this.hours()+W(this.minutes(),2)}),V("Hmmss",0,0,function(){return""+this.hours()+W(this.minutes(),2)+W(this.seconds(),2)}),WA("a",!0),WA("A",!1),F("hour","h"),R("hour",13),_("a",VA),_("A",VA),_("H",GI),_("h",GI),_("HH",GI,fI),_("hh",GI,fI),_("hmm",HI),_("hmmss",bI),_("Hmm",HI),_("Hmmss",bI),tA(["H","HH"],gg),tA(["a","A"],function(A,M,t){t._isPm=t._locale.isPM(A),t._meridiem=A}),tA(["h","hh"],function(A,M,t){M[gg]=j(A),c(t).bigHour=!0}),tA("hmm",function(A,M,t){var I=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I)),c(t).bigHour=!0}),tA("hmmss",function(A,M,t){var I=A.length-4,g=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I,2)),M[ig]=j(A.substr(g)),c(t).bigHour=!0}),tA("Hmm",function(A,M,t){var I=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I))}),tA("Hmmss",function(A,M,t){var I=A.length-4,g=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I,2)),M[ig]=j(A.substr(g))});var wg,Lg=/[ap]\.?m?\.?/i,lg=G("Hours",!0),Yg={calendar:wI,longDateFormat:LI,invalidDate:lI,ordinal:YI,ordinalParse:dI,relativeTime:hI,months:Cg,monthsShort:cg,week:Qg,weekdays:rg,weekdaysMin:xg,weekdaysShort:sg,meridiemParse:Lg},dg={},hg={},Sg=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,zg=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ug=/Z|[+-]\d\d(?::?\d\d)?/,pg=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Og=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],mg=/^\/?Date\((\-?\d+)/i;M.createFromInputFallback=w("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(A){A._d=new Date(A._i+(A._useUTC?" UTC":""))}),M.ISO_8601=function(){};var Fg=w("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var A=sM.apply(null,arguments);return this.isValid()&&A.isValid()?Athis?this:A:a()}),kg=function(){return Date.now?Date.now():+new Date};lM("Z",":"),lM("ZZ",""),_("Z",KI),_("ZZ",KI),tA(["Z","ZZ"],function(A,M,t){t._useUTC=!0,t._tzm=YM(KI,A)});var Rg=/([\+\-]|\d\d)/gi;M.updateOffset=function(){};var Jg=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Gg=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;GM.fn=uM.prototype;var Hg=vM(1,"add"),bg=vM(-1,"subtract");M.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",M.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Xg=w("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(A){return void 0===A?this.localeData():this.locale(A)});V(0,["gg",2],0,function(){return this.weekYear()%100}),V(0,["GG",2],0,function(){return this.isoWeekYear()%100}),lt("gggg","weekYear"),lt("ggggg","weekYear"),lt("GGGG","isoWeekYear"),lt("GGGGG","isoWeekYear"),F("weekYear","gg"),F("isoWeekYear","GG"),R("weekYear",1),R("isoWeekYear",1),_("G",PI),_("g",PI),_("GG",GI,fI),_("gg",GI,fI),_("GGGG",vI,RI),_("gggg",vI,RI),_("GGGGG",WI,JI),_("ggggg",WI,JI),IA(["gggg","ggggg","GGGG","GGGGG"],function(A,M,t,I){M[I.substr(0,2)]=j(A)}),IA(["gg","GG"],function(A,t,I,g){t[g]=M.parseTwoDigitYear(A)}),V("Q",0,"Qo","quarter"),F("quarter","Q"),R("quarter",7),_("Q",FI),tA("Q",function(A,M){M[tg]=3*(j(A)-1)}),V("D",["DD",2],"Do","date"),F("date","D"),R("date",9),_("D",GI),_("DD",GI,fI),_("Do",function(A,M){return A?M._ordinalParse:M._ordinalParseLenient}),tA(["D","DD"],Ig),tA("Do",function(A,M){M[Ig]=j(A.match(GI)[0],10)});var vg=G("Date",!0);V("DDD",["DDDD",3],"DDDo","dayOfYear"),F("dayOfYear","DDD"),R("dayOfYear",4),_("DDD",XI),_("DDDD",kI),tA(["DDD","DDDD"],function(A,M,t){t._dayOfYear=j(A)}),V("m",["mm",2],0,"minute"),F("minute","m"),R("minute",14),_("m",GI),_("mm",GI,fI),tA(["m","mm"],eg);var Wg=G("Minutes",!1);V("s",["ss",2],0,"second"),F("second","s"),R("second",15),_("s",GI),_("ss",GI,fI),tA(["s","ss"],ig);var Vg=G("Seconds",!1);V("S",0,0,function(){return~~(this.millisecond()/100)}),V(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),V(0,["SSS",3],0,"millisecond"),V(0,["SSSS",4],0,function(){return 10*this.millisecond()}),V(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),V(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),V(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),V(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),V(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),F("millisecond","ms"),R("millisecond",16),_("S",XI,FI),_("SS",XI,fI),_("SSS",XI,kI);var Pg;for(Pg="SSSS";Pg.length<=9;Pg+="S")_(Pg,VI);for(Pg="S";Pg.length<=9;Pg+="S")tA(Pg,mt);var Zg=G("Milliseconds",!1);V("z",0,0,"zoneAbbr"),V("zz",0,0,"zoneName");var Kg=r.prototype;Kg.add=Hg,Kg.calendar=PM,Kg.clone=ZM,Kg.diff=tt,Kg.endOf=at,Kg.format=Tt,Kg.from=Et,Kg.fromNow=Nt,Kg.to=ot,Kg.toNow=nt,Kg.get=X,Kg.invalidAt=wt,Kg.isAfter=KM,Kg.isBefore=qM,Kg.isBetween=_M,Kg.isSame=$M,Kg.isSameOrAfter=At,Kg.isSameOrBefore=Mt,Kg.isValid=yt,Kg.lang=Xg,Kg.locale=Ct,Kg.localeData=ct,Kg.max=fg,Kg.min=Fg,Kg.parsingFlags=ut,Kg.set=v,Kg.startOf=Dt,Kg.subtract=bg,Kg.toArray=st,Kg.toObject=xt,Kg.toDate=rt,Kg.toISOString=et,Kg.inspect=it,Kg.toJSON=jt,Kg.toString=gt,Kg.unix=Qt,Kg.valueOf=Bt,Kg.creationData=Lt,Kg.year=Bg,Kg.isLeapYear=rA,Kg.weekYear=Yt,Kg.isoWeekYear=dt,Kg.quarter=Kg.quarters=pt,Kg.month=nA,Kg.daysInMonth=CA,Kg.week=Kg.weeks=dA,Kg.isoWeek=Kg.isoWeeks=hA,Kg.weeksInYear=St,Kg.isoWeeksInYear=ht,Kg.date=vg,Kg.day=Kg.days=fA,Kg.weekday=kA,Kg.isoWeekday=RA,Kg.dayOfYear=Ot,Kg.hour=Kg.hours=lg,Kg.minute=Kg.minutes=Wg,Kg.second=Kg.seconds=Vg,Kg.millisecond=Kg.milliseconds=Zg,Kg.utcOffset=SM,Kg.utc=UM,Kg.local=pM,Kg.parseZone=OM,Kg.hasAlignedHourOffset=mM,Kg.isDST=FM,Kg.isLocal=kM,Kg.isUtcOffset=RM,Kg.isUtc=JM,Kg.isUTC=JM,Kg.zoneAbbr=Ft,Kg.zoneName=ft,Kg.dates=w("dates accessor is deprecated. Use date instead.",vg),Kg.months=w("months accessor is deprecated. Use month instead",nA),Kg.years=w("years accessor is deprecated. Use year instead",Bg),Kg.zone=w("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",zM),Kg.isDSTShifted=w("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",fM);var qg=h.prototype;qg.calendar=S,qg.longDateFormat=z,qg.invalidDate=U,qg.ordinal=p,qg.preparse=Jt,qg.postformat=Jt,qg.relativeTime=O,qg.pastFuture=m,qg.set=Y,qg.months=iA,qg.monthsShort=TA,qg.monthsParse=NA,qg.monthsRegex=DA,qg.monthsShortRegex=cA,qg.week=LA,qg.firstDayOfYear=YA,qg.firstDayOfWeek=lA,qg.weekdays=UA,qg.weekdaysMin=OA,qg.weekdaysShort=pA,qg.weekdaysParse=FA,qg.weekdaysRegex=JA,qg.weekdaysShortRegex=GA,qg.weekdaysMinRegex=HA,qg.isPM=PA,qg.meridiem=ZA,$A("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(A){var M=A%10,t=1===j(A%100/10)?"th":1===M?"st":2===M?"nd":3===M?"rd":"th";return A+t}}),M.lang=w("moment.lang is deprecated. Use moment.locale instead.",$A),M.langData=w("moment.langData is deprecated. Use moment.localeData instead.",tM);var _g=Math.abs,$g=eI("ms"),Ae=eI("s"),Me=eI("m"),te=eI("h"),Ie=eI("d"),ge=eI("w"),ee=eI("M"),ie=eI("y"),Te=TI("milliseconds"),Ee=TI("seconds"),Ne=TI("minutes"),oe=TI("hours"),ne=TI("days"),Ce=TI("months"),ce=TI("years"),De=Math.round,ae={s:45,m:45,h:22,d:26,M:11},Be=Math.abs,Qe=uM.prototype;return Qe.abs=Zt,Qe.add=qt,Qe.subtract=_t,Qe.as=II,Qe.asMilliseconds=$g,Qe.asSeconds=Ae,Qe.asMinutes=Me,Qe.asHours=te,Qe.asDays=Ie,Qe.asWeeks=ge,Qe.asMonths=ee,Qe.asYears=ie,Qe.valueOf=gI,Qe._bubble=AI,Qe.get=iI,Qe.milliseconds=Te,Qe.seconds=Ee,Qe.minutes=Ne,Qe.hours=oe,Qe.days=ne,Qe.weeks=EI,Qe.months=Ce,Qe.years=ce,Qe.humanize=cI,Qe.toISOString=DI,Qe.toString=DI,Qe.toJSON=DI,Qe.locale=Ct,Qe.localeData=ct,Qe.toIsoString=w("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",DI),Qe.lang=Xg,V("X",0,0,"unix"),V("x",0,0,"valueOf"),_("x",PI),_("X",qI),tA("X",function(A,M,t){t._d=new Date(1e3*parseFloat(A,10))}),tA("x",function(A,M,t){t._d=new Date(j(A))}),M.version="2.17.1",t(sM),M.fn=Kg,M.min=jM,M.max=yM,M.now=kg,M.utc=n,M.unix=kt,M.months=Xt,M.isDate=T,M.locale=$A,M.invalid=a,M.duration=GM,M.isMoment=s,M.weekdays=Wt,M.parseZone=Rt,M.localeData=tM,M.isDuration=wM,M.monthsShort=vt,M.weekdaysMin=Pt,M.defineLocale=AM,M.updateLocale=MM,M.locales=IM,M.weekdaysShort=Vt,M.normalizeUnits=f,M.relativeTimeRounding=nI,M.relativeTimeThreshold=CI,M.calendarFormat=VM,M.prototype=Kg,M})}).call(M,t(128)(A))},function(A,M,t){"use strict";var I=t(132).default,g=t(133).default,e=t(78).default;M.__esModule=!0;var i=function(A){return I(g({values:function(){var A=this;return e(this).map(function(M){return A[M]})}}),A)},T={SIZES:{large:"lg",medium:"md",small:"sm",xsmall:"xs",lg:"lg",md:"md",sm:"sm",xs:"xs"},GRID_COLUMNS:12},E=i({LARGE:"large",MEDIUM:"medium",SMALL:"small",XSMALL:"xsmall"});M.Sizes=E;var N=i({SUCCESS:"success",WARNING:"warning",DANGER:"danger",INFO:"info"});M.State=N;var o="default";M.DEFAULT=o;var n="primary";M.PRIMARY=n;var C="link";M.LINK=C;var c="inverse";M.INVERSE=c,M.default=T},function(A,M){"use strict";function t(){for(var A=arguments.length,M=Array(A),t=0;t0?void 0:(0,C.default)(!1),null!=o&&(e+=encodeURI(o))):"("===E?g+=1:")"===E?g-=1:":"===E.charAt(0)?(N=E.substring(1),o=M[N],null!=o||g>0?void 0:(0,C.default)(!1),null!=o&&(e+=encodeURIComponent(o))):e+=E;return e.replace(/\/+/g,"/")}M.__esModule=!0,M.compilePattern=i,M.matchPattern=T,M.getParamNames=E,M.getParams=N,M.formatPattern=o;var n=t(8),C=I(n),c=Object.create(null)},function(A,M){"use strict";M.__esModule=!0;var t="PUSH";M.PUSH=t;var I="REPLACE";M.REPLACE=I;var g="POP";M.POP=g,M.default={PUSH:t,REPLACE:I,POP:g}},function(A,M,t){"use strict";function I(A,M){return(A&M)===M}var g=t(2),e={MUST_USE_ATTRIBUTE:1,MUST_USE_PROPERTY:2,HAS_SIDE_EFFECTS:4,HAS_BOOLEAN_VALUE:8,HAS_NUMERIC_VALUE:16,HAS_POSITIVE_NUMERIC_VALUE:48,HAS_OVERLOADED_BOOLEAN_VALUE:64,injectDOMPropertyConfig:function(A){var M=e,t=A.Properties||{},i=A.DOMAttributeNamespaces||{},E=A.DOMAttributeNames||{},N=A.DOMPropertyNames||{},o=A.DOMMutationMethods||{};A.isCustomAttribute&&T._isCustomAttributeFunctions.push(A.isCustomAttribute);for(var n in t){T.properties.hasOwnProperty(n)?g(!1):void 0;var C=n.toLowerCase(),c=t[n],D={attributeName:C,attributeNamespace:null,propertyName:n,mutationMethod:null,mustUseAttribute:I(c,M.MUST_USE_ATTRIBUTE),mustUseProperty:I(c,M.MUST_USE_PROPERTY),hasSideEffects:I(c,M.HAS_SIDE_EFFECTS),hasBooleanValue:I(c,M.HAS_BOOLEAN_VALUE),hasNumericValue:I(c,M.HAS_NUMERIC_VALUE),hasPositiveNumericValue:I(c,M.HAS_POSITIVE_NUMERIC_VALUE),hasOverloadedBooleanValue:I(c,M.HAS_OVERLOADED_BOOLEAN_VALUE)};if(D.mustUseAttribute&&D.mustUseProperty?g(!1):void 0,!D.mustUseProperty&&D.hasSideEffects?g(!1):void 0,D.hasBooleanValue+D.hasNumericValue+D.hasOverloadedBooleanValue<=1?void 0:g(!1),E.hasOwnProperty(n)){var a=E[n];D.attributeName=a}i.hasOwnProperty(n)&&(D.attributeNamespace=i[n]),N.hasOwnProperty(n)&&(D.propertyName=N[n]),o.hasOwnProperty(n)&&(D.mutationMethod=o[n]),T.properties[n]=D}}},i={},T={ID_ATTRIBUTE_NAME:"data-reactid",properties:{},getPossibleStandardName:null,_isCustomAttributeFunctions:[],isCustomAttribute:function(A){for(var M=0;M1){var M=A.indexOf(c,1);return M>-1?A.substr(0,M):A}return null},traverseEnterLeave:function(A,M,t,I,g){var e=N(A,M);e!==A&&o(A,e,t,I,!1,!0),e!==M&&o(e,M,t,g,!0,!1)},traverseTwoPhase:function(A,M,t){A&&(o("",A,M,t,!0,!1),o(A,"",M,t,!1,!0))},traverseTwoPhaseSkipTarget:function(A,M,t){A&&(o("",A,M,t,!0,!0),o(A,"",M,t,!0,!0))},traverseAncestors:function(A,M,t){o("",A,M,t,!0,!1)},getFirstCommonAncestorID:N,_getNextDescendantID:E,isAncestorIDOf:i,SEPARATOR:c};A.exports=B},function(A,M){var t=A.exports={version:"1.2.6"};"number"==typeof __e&&(__e=t)},function(A,M,t){"use strict";var I={};A.exports=I},function(A,M,t){"use strict";function I(A,M,t){var I=0;return n.default.Children.map(A,function(A){if(n.default.isValidElement(A)){var g=I;return I++,M.call(t,A,g)}return A})}function g(A,M,t){var I=0;return n.default.Children.forEach(A,function(A){n.default.isValidElement(A)&&(M.call(t,A,I),I++)})}function e(A){var M=0;return n.default.Children.forEach(A,function(A){n.default.isValidElement(A)&&M++}),M}function i(A){var M=!1;return n.default.Children.forEach(A,function(A){!M&&n.default.isValidElement(A)&&(M=!0)}),M}function T(A,M){var t=void 0;return g(A,function(I,g){!t&&M(I,g,A)&&(t=I)}),t}function E(A,M,t){var I=0,g=[];return n.default.Children.forEach(A,function(A){n.default.isValidElement(A)&&(M.call(t,A,I)&&g.push(A),I++)}),g}var N=t(6).default;M.__esModule=!0;var o=t(1),n=N(o);M.default={map:I,forEach:g,numberOf:e,find:T,findValidComponents:E,hasValidComponent:i},A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0}),M.default=function(A){return(0,T.default)(e.default.findDOMNode(A))};var g=t(16),e=I(g),i=t(39),T=I(i);A.exports=M.default},function(A,M,t){"use strict";var I=t(204),g=t(436),e=t(217),i=t(226),T=t(227),E=t(2),N=(t(3),{}),o=null,n=function(A,M){A&&(g.executeDispatchesInOrder(A,M),A.isPersistent()||A.constructor.release(A))},C=function(A){return n(A,!0)},c=function(A){return n(A,!1)},D=null,a={injection:{injectMount:g.injection.injectMount,injectInstanceHandle:function(A){D=A},getInstanceHandle:function(){return D},injectEventPluginOrder:I.injectEventPluginOrder,injectEventPluginsByName:I.injectEventPluginsByName},eventNameDispatchConfigs:I.eventNameDispatchConfigs,registrationNameModules:I.registrationNameModules,putListener:function(A,M,t){"function"!=typeof t?E(!1):void 0;var g=N[M]||(N[M]={});g[A]=t;var e=I.registrationNameModules[M];e&&e.didPutListener&&e.didPutListener(A,M,t)},getListener:function(A,M){var t=N[M];return t&&t[A]},deleteListener:function(A,M){var t=I.registrationNameModules[M];t&&t.willDeleteListener&&t.willDeleteListener(A,M);var g=N[M];g&&delete g[A]},deleteAllListeners:function(A){for(var M in N)if(N[M][A]){var t=I.registrationNameModules[M];t&&t.willDeleteListener&&t.willDeleteListener(A,M),delete N[M][A]}},extractEvents:function(A,M,t,g,e){for(var T,E=I.plugins,N=0;N1?I-1:0),e=1;e":">","<":"<",'"':""","'":"'"},e=/[&><"']/g;A.exports=I},function(A,M,t){"use strict";var I=t(10),g=/^[ \r\n\t\f]/,e=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,i=function(A,M){A.innerHTML=M};if("undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction&&(i=function(A,M){MSApp.execUnsafeLocalFunction(function(){A.innerHTML=M})}),I.canUseDOM){var T=document.createElement("div");T.innerHTML=" ",""===T.innerHTML&&(i=function(A,M){if(A.parentNode&&A.parentNode.replaceChild(A,A),g.test(M)||"<"===M[0]&&e.test(M)){A.innerHTML=String.fromCharCode(65279)+M;var t=A.firstChild;1===t.data.length?A.removeChild(t):t.deleteData(0,1)}else A.innerHTML=M})}A.exports=i},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var g=t(1),e=I(g),i=function(A){var M=A.label,t=A.id,I=A.name,g=A.value,i=A.onChange,T=A.type,E=A.spellCheck,N=A.required,o=A.readonly,n=A.autoComplete,C=A.align,c=A.className,D=e.default.createElement("input",{id:t,name:I,value:g,onChange:i,className:"ig-text",type:T,spellCheck:E,required:N,autoComplete:n});return o&&(D=e.default.createElement("input",{id:t,name:I,value:g,onChange:i,className:"ig-text",type:T,spellCheck:E,required:N,autoComplete:n,disabled:!0})),e.default.createElement("div",{className:"input-group "+C+" "+c},D,e.default.createElement("i",{className:"ig-helpers"}),e.default.createElement("label",{className:"ig-label"},M))};M.default=i},function(A,M,t){A.exports={default:t(259),__esModule:!0}},function(A,M,t){var I=t(265),g=t(49),e=t(134),i="prototype",T=function(A,M,t){var E,N,o,n=A&T.F,C=A&T.G,c=A&T.S,D=A&T.P,a=A&T.B,B=A&T.W,Q=C?g:g[M]||(g[M]={}),r=C?I:c?I[M]:(I[M]||{})[i];C&&(t=M);for(E in t)N=!n&&r&&E in r,N&&E in Q||(o=N?r[E]:t[E],Q[E]=C&&"function"!=typeof r[E]?t[E]:a&&N?e(o,I):B&&r[E]==o?function(A){var M=function(M){return this instanceof A?new A(M):A(M)};return M[i]=A[i],M}(o):D&&"function"==typeof o?e(Function.call,o):o,D&&((Q[i]||(Q[i]={}))[E]=o))};T.F=1,T.G=2,T.S=4,T.P=8,T.B=16,T.W=32,A.exports=T},function(A,M){var t=Object;A.exports={create:t.create,getProto:t.getPrototypeOf,isEnum:{}.propertyIsEnumerable,getDesc:t.getOwnPropertyDescriptor,setDesc:t.defineProperty,setDescs:t.defineProperties,getKeys:t.keys,getNames:t.getOwnPropertyNames,getSymbols:t.getOwnPropertySymbols,each:[].forEach}},function(A,M,t){"use strict";var I=t(32),g=function(){};I&&(g=function(){return document.addEventListener?function(A,M,t,I){return A.addEventListener(M,t,I||!1)}:document.attachEvent?function(A,M,t){return A.attachEvent("on"+M,t)}:void 0}()),A.exports=g},function(A,M,t){"use strict";var I=t(145),g=t(295),e=t(290),i=t(291),T=Object.prototype.hasOwnProperty;A.exports=function(A,M,t){var E="",N=M;if("string"==typeof M){if(void 0===t)return A.style[I(M)]||e(A).getPropertyValue(g(M));(N={})[M]=t}for(var o in N)T.call(N,o)&&(N[o]||0===N[o]?E+=g(o)+":"+N[o]+";":i(A,g(o)));A.style.cssText+=";"+E}},function(A,M,t){(function(){var t=this,I=t.humanize,g={};"undefined"!=typeof A&&A.exports&&(M=A.exports=g),M.humanize=g,g.noConflict=function(){return t.humanize=I,this},g.pad=function(A,M,t,I){if(A+="",t?t.length>1&&(t=t.charAt(0)):t=" ",I=void 0===I?"left":"right","right"===I)for(;A.length4&&A<21?"th":{1:"st",2:"nd",3:"rd"}[A%10]||"th"},w:function(){return t.getDay()},z:function(){return(o.L()?i[o.n()]:e[o.n()])+o.j()-1},W:function(){var A=o.z()-o.N()+1.5;return g.pad(1+Math.floor(Math.abs(A)/7)+(A%7>3.5?1:0),2,"0")},F:function(){return N[t.getMonth()]},m:function(){return g.pad(o.n(),2,"0")},M:function(){return o.F().slice(0,3)},n:function(){return t.getMonth()+1},t:function(){return new Date(o.Y(),o.n(),0).getDate()},L:function(){return 1===new Date(o.Y(),1,29).getMonth()?1:0},o:function(){var A=o.n(),M=o.W();return o.Y()+(12===A&&M<9?-1:1===A&&M>9)},Y:function(){return t.getFullYear()},y:function(){return String(o.Y()).slice(-2)},a:function(){return t.getHours()>11?"pm":"am"},A:function(){return o.a().toUpperCase()},B:function(){var A=t.getTime()/1e3,M=A%86400+3600;M<0&&(M+=86400);var I=M/86.4%1e3;return A<0?Math.ceil(I):Math.floor(I)},g:function(){return o.G()%12||12},G:function(){return t.getHours()},h:function(){return g.pad(o.g(),2,"0")},H:function(){return g.pad(o.G(),2,"0")},i:function(){return g.pad(t.getMinutes(),2,"0")},s:function(){return g.pad(t.getSeconds(),2,"0")},u:function(){return g.pad(1e3*t.getMilliseconds(),6,"0")},O:function(){var A=t.getTimezoneOffset(),M=Math.abs(A);return(A>0?"-":"+")+g.pad(100*Math.floor(M/60)+M%60,4,"0")},P:function(){var A=o.O();return A.substr(0,3)+":"+A.substr(3,2)},Z:function(){return 60*-t.getTimezoneOffset()},c:function(){return"Y-m-d\\TH:i:sP".replace(I,T)},r:function(){return"D, d M Y H:i:s O".replace(I,T)},U:function(){return t.getTime()/1e3||0}};return A.replace(I,T)},g.numberFormat=function(A,M,t,I){M=isNaN(M)?2:Math.abs(M),t=void 0===t?".":t,I=void 0===I?",":I;var g=A<0?"-":"";A=Math.abs(+A||0);var e=parseInt(A.toFixed(M),10)+"",i=e.length>3?e.length%3:0;return g+(i?e.substr(0,i)+I:"")+e.substr(i).replace(/(\d{3})(?=\d)/g,"$1"+I)+(M?t+Math.abs(A-e).toFixed(M).slice(2):"")},g.naturalDay=function(A,M){A=void 0===A?g.time():A,M=void 0===M?"Y-m-d":M;var t=86400,I=new Date,e=new Date(I.getFullYear(),I.getMonth(),I.getDate()).getTime()/1e3;return A=e-t?"yesterday":A>=e&&A=e+t&&A-2)return(t>=0?"just ":"")+"now";if(t<60&&t>-60)return t>=0?Math.floor(t)+" seconds ago":"in "+Math.floor(-t)+" seconds";if(t<120&&t>-120)return t>=0?"about a minute ago":"in about a minute";if(t<3600&&t>-3600)return t>=0?Math.floor(t/60)+" minutes ago":"in "+Math.floor(-t/60)+" minutes";if(t<7200&&t>-7200)return t>=0?"about an hour ago":"in about an hour";if(t<86400&&t>-86400)return t>=0?Math.floor(t/3600)+" hours ago":"in "+Math.floor(-t/3600)+" hours";var I=172800;if(t-I)return t>=0?"1 day ago":"in 1 day";var e=2505600;if(t-e)return t>=0?Math.floor(t/86400)+" days ago":"in "+Math.floor(-t/86400)+" days";var i=5184e3;if(t-i)return t>=0?"about a month ago":"in about a month";var T=parseInt(g.date("Y",M),10),E=parseInt(g.date("Y",A),10),N=12*T+parseInt(g.date("n",M),10),o=12*E+parseInt(g.date("n",A),10),n=N-o;if(n<12&&n>-12)return n>=0?n+" months ago":"in "+-n+" months";var C=T-E;return C<2&&C>-2?C>=0?"a year ago":"in a year":C>=0?C+" years ago":"in "+-C+" years"},g.ordinal=function(A){A=parseInt(A,10),A=isNaN(A)?0:A;var M=A<0?"-":"";A=Math.abs(A);var t=A%100;return M+A+(t>4&&t<21?"th":{1:"st",2:"nd",3:"rd"}[A%10]||"th")},g.filesize=function(A,M,t,I,e,i){return M=void 0===M?1024:M,A<=0?"0 bytes":(A

    "),A=A.replace(/\n/g,"
    "),"

    "+A+"

    "},g.nl2br=function(A){return A.replace(/(\r\n|\n|\r)/g,"
    ")},g.truncatechars=function(A,M){return A.length<=M?A:A.substr(0,M)+"…"},g.truncatewords=function(A,M){var t=A.split(" ");return t.length0,Q=C.enumErrorProps&&(A===u||A instanceof Error),r=C.enumPrototypes&&T(A);++IM.documentElement.clientHeight;return{modalStyles:{paddingRight:I&&!g?Q.default():void 0,paddingLeft:!I&&g?Q.default():void 0}}}});X.Body=z.default,X.Header=p.default,X.Title=m.default,X.Footer=f.default,X.Dialog=h.default,X.TRANSITION_DURATION=300,X.BACKDROP_TRANSITION_DURATION=150,M.default=c.bsSizes([a.Sizes.LARGE,a.Sizes.SMALL],c.bsClass("modal",X)),A.exports=M.default},function(A,M,t){"use strict";var I=t(15).default,g=t(14).default,e=t(38).default,i=t(7).default,T=t(6).default;M.__esModule=!0;var E=t(1),N=T(E),o=t(5),n=T(o),C=t(11),c=T(C),D=t(44),a=T(D),B=function(A){function M(){g(this,M),A.apply(this,arguments)}return I(M,A),M.prototype.render=function(){var A=this.props,M=A["aria-label"],t=e(A,["aria-label"]),I=a.default(this.context.$bs_onModalHide,this.props.onHide);return N.default.createElement("div",i({},t,{className:n.default(this.props.className,c.default.prefix(this.props,"header"))}),this.props.closeButton&&N.default.createElement("button",{type:"button",className:"close","aria-label":M,onClick:I},N.default.createElement("span",{"aria-hidden":"true"},"×")),this.props.children)},M}(N.default.Component);B.propTypes={"aria-label":N.default.PropTypes.string,bsClass:N.default.PropTypes.string,closeButton:N.default.PropTypes.bool,onHide:N.default.PropTypes.func},B.contextTypes={$bs_onModalHide:N.default.PropTypes.func},B.defaultProps={"aria-label":"Close",closeButton:!1},M.default=C.bsClass("modal",B),A.exports=M.default},function(A,M,t){"use strict";function I(A,M){return Array.isArray(M)?M.indexOf(A)>=0:A===M}var g=t(7).default,e=t(78).default,i=t(6).default;M.__esModule=!0;var T=t(40),E=i(T),N=t(170),o=i(N),n=t(1),C=i(n),c=t(16),D=i(c),a=t(127),B=(i(a),t(370)),Q=i(B),r=t(44),s=i(r),x=C.default.createClass({displayName:"OverlayTrigger", -propTypes:g({},Q.default.propTypes,{trigger:C.default.PropTypes.oneOfType([C.default.PropTypes.oneOf(["click","hover","focus"]),C.default.PropTypes.arrayOf(C.default.PropTypes.oneOf(["click","hover","focus"]))]),delay:C.default.PropTypes.number,delayShow:C.default.PropTypes.number,delayHide:C.default.PropTypes.number,defaultOverlayShown:C.default.PropTypes.bool,overlay:C.default.PropTypes.node.isRequired,onBlur:C.default.PropTypes.func,onClick:C.default.PropTypes.func,onFocus:C.default.PropTypes.func,onMouseEnter:C.default.PropTypes.func,onMouseLeave:C.default.PropTypes.func,target:function(){},onHide:function(){},show:function(){}}),getDefaultProps:function(){return{defaultOverlayShown:!1,trigger:["hover","focus"]}},getInitialState:function(){return{isOverlayShown:this.props.defaultOverlayShown}},show:function(){this.setState({isOverlayShown:!0})},hide:function(){this.setState({isOverlayShown:!1})},toggle:function(){this.state.isOverlayShown?this.hide():this.show()},componentWillMount:function(){this.handleMouseOver=this.handleMouseOverOut.bind(null,this.handleDelayedShow),this.handleMouseOut=this.handleMouseOverOut.bind(null,this.handleDelayedHide)},componentDidMount:function(){this._mountNode=document.createElement("div"),this.renderOverlay()},renderOverlay:function(){D.default.unstable_renderSubtreeIntoContainer(this,this._overlay,this._mountNode)},componentWillUnmount:function(){D.default.unmountComponentAtNode(this._mountNode),this._mountNode=null,clearTimeout(this._hoverShowDelay),clearTimeout(this._hoverHideDelay)},componentDidUpdate:function(){this._mountNode&&this.renderOverlay()},getOverlayTarget:function(){return D.default.findDOMNode(this)},getOverlay:function(){var A=g({},o.default(this.props,e(Q.default.propTypes)),{show:this.state.isOverlayShown,onHide:this.hide,target:this.getOverlayTarget,onExit:this.props.onExit,onExiting:this.props.onExiting,onExited:this.props.onExited,onEnter:this.props.onEnter,onEntering:this.props.onEntering,onEntered:this.props.onEntered}),M=n.cloneElement(this.props.overlay,{placement:A.placement,container:A.container});return C.default.createElement(Q.default,A,M)},render:function(){var A=C.default.Children.only(this.props.children),M=A.props,t={"aria-describedby":this.props.overlay.props.id};return this._overlay=this.getOverlay(),t.onClick=s.default(M.onClick,this.props.onClick),I("click",this.props.trigger)&&(t.onClick=s.default(this.toggle,t.onClick)),I("hover",this.props.trigger)&&(t.onMouseOver=s.default(this.handleMouseOver,this.props.onMouseOver,M.onMouseOver),t.onMouseOut=s.default(this.handleMouseOut,this.props.onMouseOut,M.onMouseOut)),I("focus",this.props.trigger)&&(t.onFocus=s.default(this.handleDelayedShow,this.props.onFocus,M.onFocus),t.onBlur=s.default(this.handleDelayedHide,this.props.onBlur,M.onBlur)),n.cloneElement(A,t)},handleDelayedShow:function(){var A=this;if(null!=this._hoverHideDelay)return clearTimeout(this._hoverHideDelay),void(this._hoverHideDelay=null);if(!this.state.isOverlayShown&&null==this._hoverShowDelay){var M=null!=this.props.delayShow?this.props.delayShow:this.props.delay;return M?void(this._hoverShowDelay=setTimeout(function(){A._hoverShowDelay=null,A.show()},M)):void this.show()}},handleDelayedHide:function(){var A=this;if(null!=this._hoverShowDelay)return clearTimeout(this._hoverShowDelay),void(this._hoverShowDelay=null);if(this.state.isOverlayShown&&null==this._hoverHideDelay){var M=null!=this.props.delayHide?this.props.delayHide:this.props.delay;return M?void(this._hoverHideDelay=setTimeout(function(){A._hoverHideDelay=null,A.hide()},M)):void this.hide()}},handleMouseOverOut:function(A,M){var t=M.currentTarget,I=M.relatedTarget||M.nativeEvent.toElement;I&&(I===t||E.default(t,I))||A(M)}});M.default=x,A.exports=M.default},function(A,M,t){"use strict";var I=t(7).default,g=t(6).default;M.__esModule=!0;var e=t(1),i=g(e),T=t(5),E=g(T),N=t(11),o=g(N),n=t(183),C=g(n),c=i.default.createClass({displayName:"Tooltip",propTypes:{id:C.default(i.default.PropTypes.oneOfType([i.default.PropTypes.string,i.default.PropTypes.number])),placement:i.default.PropTypes.oneOf(["top","right","bottom","left"]),positionLeft:i.default.PropTypes.number,positionTop:i.default.PropTypes.number,arrowOffsetLeft:i.default.PropTypes.oneOfType([i.default.PropTypes.number,i.default.PropTypes.string]),arrowOffsetTop:i.default.PropTypes.oneOfType([i.default.PropTypes.number,i.default.PropTypes.string]),title:i.default.PropTypes.node},getDefaultProps:function(){return{bsClass:"tooltip",placement:"right"}},render:function(){var A,M=(A={},A[o.default.prefix(this.props)]=!0,A[this.props.placement]=!0,A),t=I({left:this.props.positionLeft,top:this.props.positionTop},this.props.style),g={left:this.props.arrowOffsetLeft,top:this.props.arrowOffsetTop};return i.default.createElement("div",I({role:"tooltip"},this.props,{className:E.default(this.props.className,M),style:t}),i.default.createElement("div",{className:o.default.prefix(this.props,"arrow"),style:g}),i.default.createElement("div",{className:o.default.prefix(this.props,"inner")},this.props.children))}});M.default=c,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){return A="function"==typeof A?A():A,i.default.findDOMNode(A)||M}Object.defineProperty(M,"__esModule",{value:!0}),M.default=g;var e=t(16),i=I(e);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M,t,I,g){var i=A[M],E="undefined"==typeof i?"undefined":e(i);return T.default.isValidElement(i)?new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of type ReactElement "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected a ReactComponent or a ")+"DOMElement. You can usually obtain a ReactComponent or DOMElement from a ReactElement by attaching a ref to it."):"object"===E&&"function"==typeof i.render||1===i.nodeType?null:new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of value ` + "`" + `"+i+"` + "`" + ` "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected a ReactComponent or a ")+"DOMElement.")}M.__esModule=!0;var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol?"symbol":typeof A},i=t(1),T=I(i),E=t(182),N=I(E);M.default=(0,N.default)(g)},function(A,M,t){"use strict";function I(){function A(A,M,I){for(var g=0;g>",null!=t[I]?A(t,I,g):M?new Error("Required prop '"+I+"' was not specified in '"+g+"'."):void 0}var t=M.bind(null,!1);return t.isRequired=M.bind(null,!0),t}M.__esModule=!0,M.errMsg=t,M.createChainableTypeChecker=I},function(A,M){"use strict";function t(A,M,t){function I(){return i=!0,T?void(N=[].concat(Array.prototype.slice.call(arguments))):void t.apply(this,arguments)}function g(){if(!i&&(E=!0,!T)){for(T=!0;!i&&e=A&&E&&(i=!0,t()))}}var e=0,i=!1,T=!1,E=!1,N=void 0;g()}function I(A,M,t){function I(A,M,I){i||(M?(i=!0,t(M)):(e[A]=I,i=++T===g,i&&t(null,e)))}var g=A.length,e=[];if(0===g)return t(null,e);var i=!1,T=0;A.forEach(function(A,t){M(A,t,function(A,M){I(t,A,M)})})}M.__esModule=!0,M.loopAsync=t,M.mapAsync=I},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}M.__esModule=!0,M.router=M.routes=M.route=M.components=M.component=M.location=M.history=M.falsy=M.locationShape=M.routerShape=void 0;var e=t(1),i=t(66),T=(g(i),t(34)),E=I(T),N=t(9),o=(g(N),e.PropTypes.func),n=e.PropTypes.object,C=e.PropTypes.shape,c=e.PropTypes.string,D=M.routerShape=C({push:o.isRequired,replace:o.isRequired,go:o.isRequired,goBack:o.isRequired,goForward:o.isRequired,setRouteLeaveHook:o.isRequired,isActive:o.isRequired}),a=M.locationShape=C({pathname:c.isRequired,search:c.isRequired,state:n,action:c.isRequired,key:c}),B=M.falsy=E.falsy,Q=M.history=E.history,r=M.location=a,s=M.component=E.component,x=M.components=E.components,j=M.route=E.route,y=(M.routes=E.routes,M.router=D),u={falsy:B,history:Q,location:r,component:s,components:x,route:j,router:y};M.default=u},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A){for(var M in A)if(Object.prototype.hasOwnProperty.call(A,M))return!0;return!1}function e(A,M){function t(M){var t=!(arguments.length<=1||void 0===arguments[1])&&arguments[1],I=arguments.length<=2||void 0===arguments[2]?null:arguments[2],g=void 0;return t&&t!==!0||null!==I?(M={pathname:M,query:t},g=I||!1):(M=A.createLocation(M),g=t),(0,C.default)(M,g,s.location,s.routes,s.params)}function I(A,t){x&&x.location===A?e(x,t):(0,B.default)(M,A,function(M,I){M?t(M):I?e(i({},I,{location:A}),t):t()})}function e(A,M){function t(t,g){return t||g?I(t,g):void(0,D.default)(A,function(t,I){t?M(t):M(null,null,s=i({},A,{components:I}))})}function I(A,t){A?M(A):M(null,t)}var g=(0,N.default)(s,A),e=g.leaveRoutes,T=g.changeRoutes,E=g.enterRoutes;(0,o.runLeaveHooks)(e,s),e.filter(function(A){return E.indexOf(A)===-1}).forEach(a),(0,o.runChangeHooks)(T,s,A,function(M,g){return M||g?I(M,g):void(0,o.runEnterHooks)(E,A,t)})}function T(A){var M=arguments.length<=1||void 0===arguments[1]||arguments[1];return A.__id__||M&&(A.__id__=j++)}function E(A){return A.reduce(function(A,M){return A.push.apply(A,y[T(M)]),A},[])}function n(A,t){(0,B.default)(M,A,function(M,I){if(null==I)return void t();x=i({},I,{location:A});for(var g=E((0,N.default)(s,x).leaveRoutes),e=void 0,T=0,o=g.length;null==e&&T=32||13===M?M:0}A.exports=t},function(A,M){"use strict";function t(A){var M=this,t=M.nativeEvent;if(t.getModifierState)return t.getModifierState(A);var I=g[A];return!!I&&!!t[I]}function I(A){return t}var g={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};A.exports=I},function(A,M){"use strict";function t(A){var M=A.target||A.srcElement||window;return 3===M.nodeType?M.parentNode:M}A.exports=t},function(A,M){"use strict";function t(A){var M=A&&(I&&A[I]||A[g]);if("function"==typeof M)return M}var I="function"==typeof Symbol&&Symbol.iterator,g="@@iterator";A.exports=t},function(A,M,t){"use strict";function I(A){return"function"==typeof A&&"undefined"!=typeof A.prototype&&"function"==typeof A.prototype.mountComponent&&"function"==typeof A.prototype.receiveComponent}function g(A){var M;if(null===A||A===!1)M=new i(g);else if("object"==typeof A){var t=A;!t||"function"!=typeof t.type&&"string"!=typeof t.type?N(!1):void 0,M="string"==typeof t.type?T.createInternalComponent(t):I(t.type)?new t.type(t):new o}else"string"==typeof A||"number"==typeof A?M=T.createInstanceForText(A):N(!1);return M.construct(A),M._mountIndex=0,M._mountImage=null,M}var e=t(442),i=t(215),T=t(221),E=t(4),N=t(2),o=(t(3),function(){});E(o.prototype,e.Mixin,{_instantiateReactComponent:g}),A.exports=g},function(A,M,t){"use strict";/** +!function(){"use strict";function t(){for(var A=[],M=0;M2?t-2:0),g=2;g1){for(var c=Array(C),D=0;D1){for(var a=Array(D),B=0;B3&&void 0!==arguments[3]?arguments[3]:{},N=Boolean(A),C=A||w,D=void 0;D="function"==typeof M?M:M?(0,Q.default)(M):L;var B=t||l,r=I.pure,s=void 0===r||r,x=I.withRef,y=void 0!==x&&x,h=s&&B!==l,S=d++;return function(A){function M(A,M,t){var I=B(A,M,t);return I}var t="Connect("+T(A)+")",I=function(I){function T(A,M){g(this,T);var i=e(this,I.call(this,A,M));i.version=S,i.store=A.store||M.store,(0,u.default)(i.store,'Could not find "store" in either the context or '+('props of "'+t+'". ')+"Either wrap the root component in a , "+('or explicitly pass "store" as a prop to "'+t+'".'));var E=i.store.getState();return i.state={storeState:E},i.clearCache(),i}return i(T,I),T.prototype.shouldComponentUpdate=function(){return!s||this.haveOwnPropsChanged||this.hasStoreStateChanged},T.prototype.computeStateProps=function(A,M){if(!this.finalMapStateToProps)return this.configureFinalMapState(A,M);var t=A.getState(),I=this.doStatePropsDependOnOwnProps?this.finalMapStateToProps(t,M):this.finalMapStateToProps(t);return I},T.prototype.configureFinalMapState=function(A,M){var t=C(A.getState(),M),I="function"==typeof t;return this.finalMapStateToProps=I?t:C,this.doStatePropsDependOnOwnProps=1!==this.finalMapStateToProps.length,I?this.computeStateProps(A,M):t},T.prototype.computeDispatchProps=function(A,M){if(!this.finalMapDispatchToProps)return this.configureFinalMapDispatch(A,M);var t=A.dispatch,I=this.doDispatchPropsDependOnOwnProps?this.finalMapDispatchToProps(t,M):this.finalMapDispatchToProps(t);return I},T.prototype.configureFinalMapDispatch=function(A,M){var t=D(A.dispatch,M),I="function"==typeof t;return this.finalMapDispatchToProps=I?t:D,this.doDispatchPropsDependOnOwnProps=1!==this.finalMapDispatchToProps.length,I?this.computeDispatchProps(A,M):t},T.prototype.updateStatePropsIfNeeded=function(){var A=this.computeStateProps(this.store,this.props);return(!this.stateProps||!(0,a.default)(A,this.stateProps))&&(this.stateProps=A,!0)},T.prototype.updateDispatchPropsIfNeeded=function(){var A=this.computeDispatchProps(this.store,this.props);return(!this.dispatchProps||!(0,a.default)(A,this.dispatchProps))&&(this.dispatchProps=A,!0)},T.prototype.updateMergedPropsIfNeeded=function(){var A=M(this.stateProps,this.dispatchProps,this.props);return!(this.mergedProps&&h&&(0,a.default)(A,this.mergedProps))&&(this.mergedProps=A,!0)},T.prototype.isSubscribed=function(){return"function"==typeof this.unsubscribe},T.prototype.trySubscribe=function(){N&&!this.unsubscribe&&(this.unsubscribe=this.store.subscribe(this.handleChange.bind(this)),this.handleChange())},T.prototype.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null)},T.prototype.componentDidMount=function(){this.trySubscribe()},T.prototype.componentWillReceiveProps=function(A){s&&(0,a.default)(A,this.props)||(this.haveOwnPropsChanged=!0)},T.prototype.componentWillUnmount=function(){this.tryUnsubscribe(),this.clearCache()},T.prototype.clearCache=function(){this.dispatchProps=null,this.stateProps=null,this.mergedProps=null,this.haveOwnPropsChanged=!0,this.hasStoreStateChanged=!0,this.haveStatePropsBeenPrecalculated=!1,this.statePropsPrecalculationError=null,this.renderedElement=null,this.finalMapDispatchToProps=null,this.finalMapStateToProps=null},T.prototype.handleChange=function(){if(this.unsubscribe){var A=this.store.getState(),M=this.state.storeState;if(!s||M!==A){if(s&&!this.doStatePropsDependOnOwnProps){var t=E(this.updateStatePropsIfNeeded,this);if(!t)return;t===Y&&(this.statePropsPrecalculationError=Y.value),this.haveStatePropsBeenPrecalculated=!0}this.hasStoreStateChanged=!0,this.setState({storeState:A})}}},T.prototype.getWrappedInstance=function(){return(0,u.default)(y,"To access the wrapped instance, you need to specify { withRef: true } as the fourth argument of the connect() call."),this.refs.wrappedInstance},T.prototype.render=function(){var M=this.haveOwnPropsChanged,t=this.hasStoreStateChanged,I=this.haveStatePropsBeenPrecalculated,g=this.statePropsPrecalculationError,e=this.renderedElement;if(this.haveOwnPropsChanged=!1,this.hasStoreStateChanged=!1,this.haveStatePropsBeenPrecalculated=!1,this.statePropsPrecalculationError=null,g)throw g;var i=!0,T=!0;s&&e&&(i=t||M&&this.doStatePropsDependOnOwnProps,T=M&&this.doDispatchPropsDependOnOwnProps);var E=!1,N=!1;I?E=!0:i&&(E=this.updateStatePropsIfNeeded()),T&&(N=this.updateDispatchPropsIfNeeded());var C=!0;return C=!!(E||N||M)&&this.updateMergedPropsIfNeeded(),!C&&e?e:(y?this.renderedElement=(0,n.createElement)(A,o({},this.mergedProps,{ref:"wrappedInstance"})):this.renderedElement=(0,n.createElement)(A,this.mergedProps),this.renderedElement)},T}(n.Component);return I.displayName=t,I.WrappedComponent=A,I.contextTypes={store:c.default},I.propTypes={store:c.default},(0,j.default)(I,A)}}M.__esModule=!0;var o=Object.assign||function(A){for(var M=1;M should not have a "'+M+'" prop')}M.__esModule=!0,M.routes=M.route=M.components=M.component=M.history=void 0,M.falsy=I;var g=t(1),e=g.PropTypes.func,i=g.PropTypes.object,T=g.PropTypes.arrayOf,E=g.PropTypes.oneOfType,N=g.PropTypes.element,o=g.PropTypes.shape,n=g.PropTypes.string,C=(M.history=o({listen:e.isRequired,push:e.isRequired,replace:e.isRequired,go:e.isRequired,goBack:e.isRequired,goForward:e.isRequired}),M.component=E([e,n])),c=(M.components=E([C,i]),M.route=E([i,N]));M.routes=E([c,T(c)])},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A){var M=A.match(/^https?:\/\/[^\/]*/);return null==M?A:A.substring(M[0].length)}function e(A){var M=g(A),t="",I="",e=M.indexOf("#");e!==-1&&(I=M.substring(e),M=M.substring(0,e));var i=M.indexOf("?");return i!==-1&&(t=M.substring(i),M=M.substring(0,i)),""===M&&(M="/"),{pathname:M,search:t,hash:I}}M.__esModule=!0,M.extractPath=g,M.parsePath=e;var i=t(23);I(i)},function(A,M,t){"use strict";function I(){g.attachRefs(this,this._currentElement)}var g=t(459),e={mountComponent:function(A,M,t,g){var e=A.mountComponent(M,t,g);return A._currentElement&&null!=A._currentElement.ref&&t.getReactMountReady().enqueue(I,A),e},unmountComponent:function(A){g.detachRefs(A,A._currentElement),A.unmountComponent()},receiveComponent:function(A,M,t,e){var i=A._currentElement;if(M!==i||e!==A._context){var T=g.shouldUpdateRefs(i,M);T&&g.detachRefs(A,i),A.receiveComponent(M,t,e),T&&A._currentElement&&null!=A._currentElement.ref&&t.getReactMountReady().enqueue(I,A)}},performUpdateIfNecessary:function(A,M){A.performUpdateIfNecessary(M)}};A.exports=e},function(A,M,t){"use strict";function I(A,M,t,I){this.dispatchConfig=A,this.dispatchMarker=M,this.nativeEvent=t;var g=this.constructor.Interface;for(var e in g)if(g.hasOwnProperty(e)){var T=g[e];T?this[e]=T(t):"target"===e?this.target=I:this[e]=t[e]}var E=null!=t.defaultPrevented?t.defaultPrevented:t.returnValue===!1;E?this.isDefaultPrevented=i.thatReturnsTrue:this.isDefaultPrevented=i.thatReturnsFalse,this.isPropagationStopped=i.thatReturnsFalse}var g=t(31),e=t(4),i=t(20),T=(t(3),{type:null,target:null,currentTarget:i.thatReturnsNull,eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(A){return A.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null});e(I.prototype,{preventDefault:function(){this.defaultPrevented=!0;var A=this.nativeEvent;A&&(A.preventDefault?A.preventDefault():A.returnValue=!1,this.isDefaultPrevented=i.thatReturnsTrue)},stopPropagation:function(){var A=this.nativeEvent;A&&(A.stopPropagation?A.stopPropagation():A.cancelBubble=!0,this.isPropagationStopped=i.thatReturnsTrue)},persist:function(){this.isPersistent=i.thatReturnsTrue},isPersistent:i.thatReturnsFalse,destructor:function(){var A=this.constructor.Interface;for(var M in A)this[M]=null;this.dispatchConfig=null,this.dispatchMarker=null,this.nativeEvent=null}}),I.Interface=T,I.augmentClass=function(A,M){var t=this,I=Object.create(t.prototype);e(I,A.prototype),A.prototype=I,A.prototype.constructor=A,A.Interface=e({},t.Interface,M),A.augmentClass=t.augmentClass,g.addPoolingTo(A,g.fourArgumentPooler)},g.addPoolingTo(I,g.fourArgumentPooler),A.exports=I},function(A,M){"use strict";M.default=function(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t},M.__esModule=!0},function(A,M){"use strict";function t(A){return A&&A.ownerDocument||document}M.__esModule=!0,M.default=t,A.exports=M.default},function(A,M,t){"use strict";var I=t(32),g=function(){var A=I&&document.documentElement;return A&&A.contains?function(A,M){return A.contains(M)}:A&&A.compareDocumentPosition?function(A,M){return A===M||!!(16&A.compareDocumentPosition(M))}:function(A,M){if(M)do if(M===A)return!0;while(M=M.parentNode);return!1}}();A.exports=g},function(A,M){function t(A){return"number"==typeof A&&A>-1&&A%1==0&&A<=I}var I=9007199254740991;A.exports=t},function(A,M,t){(function(A){!function(M,t){A.exports=t()}(this,function(){"use strict";function M(){return aI.apply(null,arguments)}function t(A){aI=A}function I(A){return A instanceof Array||"[object Array]"===Object.prototype.toString.call(A)}function g(A){return null!=A&&"[object Object]"===Object.prototype.toString.call(A)}function e(A){var M;for(M in A)return!1;return!0}function i(A){return"number"==typeof A||"[object Number]"===Object.prototype.toString.call(A)}function T(A){return A instanceof Date||"[object Date]"===Object.prototype.toString.call(A)}function E(A,M){var t,I=[];for(t=0;t0)for(t in rI)I=rI[t],g=M[I],B(g)||(A[I]=g);return A}function r(A){Q(this,A),this._d=new Date(null!=A._d?A._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),sI===!1&&(sI=!0,M.updateOffset(this),sI=!1)}function s(A){return A instanceof r||null!=A&&null!=A._isAMomentObject}function x(A){return A<0?Math.ceil(A)||0:Math.floor(A)}function j(A){var M=+A,t=0;return 0!==M&&isFinite(M)&&(t=x(M)),t}function y(A,M,t){var I,g=Math.min(A.length,M.length),e=Math.abs(A.length-M.length),i=0;for(I=0;I0?"future":"past"];return l(t)?t(M):t.replace(/%s/i,M)}function F(A,M){var t=A.toLowerCase();SI[t]=SI[t+"s"]=SI[M]=A}function f(A){return"string"==typeof A?SI[A]||SI[A.toLowerCase()]:void 0}function k(A){var M,t,I={};for(t in A)N(A,t)&&(M=f(t),M&&(I[M]=A[t]));return I}function R(A,M){zI[A]=M}function J(A){var M=[];for(var t in A)M.push({unit:t,priority:zI[t]});return M.sort(function(A,M){return A.priority-M.priority}),M}function G(A,t){return function(I){return null!=I?(b(this,A,I),M.updateOffset(this,t),this):H(this,A)}}function H(A,M){return A.isValid()?A._d["get"+(A._isUTC?"UTC":"")+M]():NaN}function b(A,M,t){A.isValid()&&A._d["set"+(A._isUTC?"UTC":"")+M](t)}function X(A){return A=f(A),l(this[A])?this[A]():this}function v(A,M){if("object"==typeof A){A=k(A);for(var t=J(A),I=0;I=0;return(e?t?"+":"":"-")+Math.pow(10,Math.max(0,g)).toString().substr(1)+I}function V(A,M,t,I){var g=I;"string"==typeof I&&(g=function(){return this[I]()}),A&&(mI[A]=g),M&&(mI[M[0]]=function(){return W(g.apply(this,arguments),M[1],M[2])}),t&&(mI[t]=function(){return this.localeData().ordinal(g.apply(this,arguments),A)})}function P(A){return A.match(/\[[\s\S]/)?A.replace(/^\[|\]$/g,""):A.replace(/\\/g,"")}function Z(A){var M,t,I=A.match(pI);for(M=0,t=I.length;M=0&&UI.test(A);)A=A.replace(UI,t),UI.lastIndex=0,I-=1;return A}function _(A,M,t){$I[A]=l(M)?M:function(A,I){return A&&t?t:M}}function $(A,M){return N($I,A)?$I[A](M._strict,M._locale):new RegExp(AA(A))}function AA(A){return MA(A.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(A,M,t,I,g){return M||t||I||g}))}function MA(A){return A.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function tA(A,M){var t,I=M;for("string"==typeof A&&(A=[A]),i(M)&&(I=function(A,t){t[M]=j(A)}),t=0;t=0&&isFinite(T.getFullYear())&&T.setFullYear(A),T}function xA(A){var M=new Date(Date.UTC.apply(null,arguments));return A<100&&A>=0&&isFinite(M.getUTCFullYear())&&M.setUTCFullYear(A),M}function jA(A,M,t){var I=7+M-t,g=(7+xA(A,0,I).getUTCDay()-M)%7;return-g+I-1}function yA(A,M,t,I,g){var e,i,T=(7+t-I)%7,E=jA(A,I,g),N=1+7*(M-1)+T+E;return N<=0?(e=A-1,i=BA(e)+N):N>BA(A)?(e=A+1,i=N-BA(A)):(e=A,i=N),{year:e,dayOfYear:i}}function uA(A,M,t){var I,g,e=jA(A.year(),M,t),i=Math.floor((A.dayOfYear()-e-1)/7)+1;return i<1?(g=A.year()-1,I=i+wA(g,M,t)):i>wA(A.year(),M,t)?(I=i-wA(A.year(),M,t),g=A.year()+1):(g=A.year(),I=i),{week:I,year:g}}function wA(A,M,t){var I=jA(A,M,t),g=jA(A+1,M,t);return(BA(A)-I+g)/7}function LA(A){return uA(A,this._week.dow,this._week.doy).week}function lA(){return this._week.dow}function YA(){return this._week.doy}function dA(A){var M=this.localeData().week(this);return null==A?M:this.add(7*(A-M),"d")}function hA(A){var M=uA(this,1,4).week;return null==A?M:this.add(7*(A-M),"d")}function SA(A,M){return"string"!=typeof A?A:isNaN(A)?(A=M.weekdaysParse(A),"number"==typeof A?A:null):parseInt(A,10)}function zA(A,M){return"string"==typeof A?M.weekdaysParse(A)%7||7:isNaN(A)?null:A}function pA(A,M){return A?I(this._weekdays)?this._weekdays[A.day()]:this._weekdays[this._weekdays.isFormat.test(M)?"format":"standalone"][A.day()]:this._weekdays}function UA(A){return A?this._weekdaysShort[A.day()]:this._weekdaysShort}function OA(A){return A?this._weekdaysMin[A.day()]:this._weekdaysMin}function mA(A,M,t){var I,g,e,i=A.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],I=0;I<7;++I)e=n([2e3,1]).day(I),this._minWeekdaysParse[I]=this.weekdaysMin(e,"").toLocaleLowerCase(),this._shortWeekdaysParse[I]=this.weekdaysShort(e,"").toLocaleLowerCase(),this._weekdaysParse[I]=this.weekdays(e,"").toLocaleLowerCase();return t?"dddd"===M?(g=og.call(this._weekdaysParse,i),g!==-1?g:null):"ddd"===M?(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:null):(g=og.call(this._minWeekdaysParse,i),g!==-1?g:null):"dddd"===M?(g=og.call(this._weekdaysParse,i),g!==-1?g:(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:(g=og.call(this._minWeekdaysParse,i),g!==-1?g:null))):"ddd"===M?(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:(g=og.call(this._weekdaysParse,i),g!==-1?g:(g=og.call(this._minWeekdaysParse,i),g!==-1?g:null))):(g=og.call(this._minWeekdaysParse,i),g!==-1?g:(g=og.call(this._weekdaysParse,i),g!==-1?g:(g=og.call(this._shortWeekdaysParse,i),g!==-1?g:null)))}function FA(A,M,t){var I,g,e;if(this._weekdaysParseExact)return mA.call(this,A,M,t);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),I=0;I<7;I++){if(g=n([2e3,1]).day(I),t&&!this._fullWeekdaysParse[I]&&(this._fullWeekdaysParse[I]=new RegExp("^"+this.weekdays(g,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[I]=new RegExp("^"+this.weekdaysShort(g,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[I]=new RegExp("^"+this.weekdaysMin(g,"").replace(".",".?")+"$","i")),this._weekdaysParse[I]||(e="^"+this.weekdays(g,"")+"|^"+this.weekdaysShort(g,"")+"|^"+this.weekdaysMin(g,""),this._weekdaysParse[I]=new RegExp(e.replace(".",""),"i")),t&&"dddd"===M&&this._fullWeekdaysParse[I].test(A))return I;if(t&&"ddd"===M&&this._shortWeekdaysParse[I].test(A))return I;if(t&&"dd"===M&&this._minWeekdaysParse[I].test(A))return I;if(!t&&this._weekdaysParse[I].test(A))return I}}function fA(A){if(!this.isValid())return null!=A?this:NaN;var M=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=A?(A=SA(A,this.localeData()),this.add(A-M,"d")):M}function kA(A){if(!this.isValid())return null!=A?this:NaN;var M=(this.day()+7-this.localeData()._week.dow)%7;return null==A?M:this.add(A-M,"d")}function RA(A){if(!this.isValid())return null!=A?this:NaN;if(null!=A){var M=zA(A,this.localeData());return this.day(this.day()%7?M:M-7)}return this.day()||7}function JA(A){return this._weekdaysParseExact?(N(this,"_weekdaysRegex")||bA.call(this),A?this._weekdaysStrictRegex:this._weekdaysRegex):(N(this,"_weekdaysRegex")||(this._weekdaysRegex=jg),this._weekdaysStrictRegex&&A?this._weekdaysStrictRegex:this._weekdaysRegex)}function GA(A){return this._weekdaysParseExact?(N(this,"_weekdaysRegex")||bA.call(this),A?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(N(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=yg),this._weekdaysShortStrictRegex&&A?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function HA(A){return this._weekdaysParseExact?(N(this,"_weekdaysRegex")||bA.call(this),A?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(N(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=ug),this._weekdaysMinStrictRegex&&A?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function bA(){function A(A,M){return M.length-A.length}var M,t,I,g,e,i=[],T=[],E=[],N=[];for(M=0;M<7;M++)t=n([2e3,1]).day(M),I=this.weekdaysMin(t,""),g=this.weekdaysShort(t,""),e=this.weekdays(t,""),i.push(I),T.push(g),E.push(e),N.push(I),N.push(g),N.push(e);for(i.sort(A),T.sort(A),E.sort(A),N.sort(A),M=0;M<7;M++)T[M]=MA(T[M]),E[M]=MA(E[M]),N[M]=MA(N[M]);this._weekdaysRegex=new RegExp("^("+N.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+E.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+T.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+i.join("|")+")","i")}function XA(){return this.hours()%12||12}function vA(){return this.hours()||24}function WA(A,M){V(A,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),M)})}function VA(A,M){return M._meridiemParse}function PA(A){return"p"===(A+"").toLowerCase().charAt(0)}function ZA(A,M,t){return A>11?t?"pm":"PM":t?"am":"AM"}function KA(A){return A?A.toLowerCase().replace("_","-"):A}function qA(A){for(var M,t,I,g,e=0;e0;){if(I=_A(g.slice(0,M).join("-")))return I;if(t&&t.length>=M&&y(g,t,!0)>=M-1)break;M--}e++}return null}function _A(M){var t=null;if(!dg[M]&&"undefined"!=typeof A&&A&&A.exports)try{t=wg._abbr,!function(){var A=new Error('Cannot find module "./locale"');throw A.code="MODULE_NOT_FOUND",A}(),$A(t)}catch(A){}return dg[M]}function $A(A,M){var t;return A&&(t=B(M)?tM(A):AM(A,M),t&&(wg=t)),wg._abbr}function AM(A,M){if(null!==M){var t=Yg;if(M.abbr=A,null!=dg[A])L("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),t=dg[A]._config;else if(null!=M.parentLocale){if(null==dg[M.parentLocale])return hg[M.parentLocale]||(hg[M.parentLocale]=[]),hg[M.parentLocale].push({name:A,config:M}),null;t=dg[M.parentLocale]._config}return dg[A]=new h(d(t,M)),hg[A]&&hg[A].forEach(function(A){AM(A.name,A.config)}),$A(A),dg[A]}return delete dg[A],null}function MM(A,M){if(null!=M){var t,I=Yg;null!=dg[A]&&(I=dg[A]._config),M=d(I,M),t=new h(M),t.parentLocale=dg[A],dg[A]=t,$A(A)}else null!=dg[A]&&(null!=dg[A].parentLocale?dg[A]=dg[A].parentLocale:null!=dg[A]&&delete dg[A]);return dg[A]}function tM(A){var M;if(A&&A._locale&&A._locale._abbr&&(A=A._locale._abbr),!A)return wg;if(!I(A)){if(M=_A(A))return M;A=[A]}return qA(A)}function IM(){return uI(dg)}function gM(A){var M,t=A._a;return t&&c(A).overflow===-2&&(M=t[tg]<0||t[tg]>11?tg:t[Ig]<1||t[Ig]>eA(t[Mg],t[tg])?Ig:t[gg]<0||t[gg]>24||24===t[gg]&&(0!==t[eg]||0!==t[ig]||0!==t[Tg])?gg:t[eg]<0||t[eg]>59?eg:t[ig]<0||t[ig]>59?ig:t[Tg]<0||t[Tg]>999?Tg:-1,c(A)._overflowDayOfYear&&(MIg)&&(M=Ig),c(A)._overflowWeeks&&M===-1&&(M=Eg),c(A)._overflowWeekday&&M===-1&&(M=Ng),c(A).overflow=M),A}function eM(A){var M,t,I,g,e,i,T=A._i,E=Sg.exec(T)||zg.exec(T);if(E){for(c(A).iso=!0,M=0,t=Ug.length;MBA(g)&&(c(A)._overflowDayOfYear=!0),t=xA(g,0,A._dayOfYear),A._a[tg]=t.getUTCMonth(),A._a[Ig]=t.getUTCDate()),M=0;M<3&&null==A._a[M];++M)A._a[M]=e[M]=I[M];for(;M<7;M++)A._a[M]=e[M]=null==A._a[M]?2===M?1:0:A._a[M];24===A._a[gg]&&0===A._a[eg]&&0===A._a[ig]&&0===A._a[Tg]&&(A._nextDay=!0,A._a[gg]=0),A._d=(A._useUTC?xA:sA).apply(null,e),null!=A._tzm&&A._d.setUTCMinutes(A._d.getUTCMinutes()-A._tzm),A._nextDay&&(A._a[gg]=24)}}function oM(A){var M,t,I,g,e,i,T,E;if(M=A._w,null!=M.GG||null!=M.W||null!=M.E)e=1,i=4,t=TM(M.GG,A._a[Mg],uA(sM(),1,4).year),I=TM(M.W,1),g=TM(M.E,1),(g<1||g>7)&&(E=!0);else{e=A._locale._week.dow,i=A._locale._week.doy;var N=uA(sM(),e,i);t=TM(M.gg,A._a[Mg],N.year),I=TM(M.w,N.week),null!=M.d?(g=M.d,(g<0||g>6)&&(E=!0)):null!=M.e?(g=M.e+e,(M.e<0||M.e>6)&&(E=!0)):g=e}I<1||I>wA(t,e,i)?c(A)._overflowWeeks=!0:null!=E?c(A)._overflowWeekday=!0:(T=yA(t,I,g,e,i),A._a[Mg]=T.year,A._dayOfYear=T.dayOfYear)}function nM(A){if(A._f===M.ISO_8601)return void eM(A);A._a=[],c(A).empty=!0;var t,I,g,e,i,T=""+A._i,E=T.length,N=0;for(g=q(A._f,A._locale).match(pI)||[],t=0;t0&&c(A).unusedInput.push(i),T=T.slice(T.indexOf(I)+I.length),N+=I.length),mI[e]?(I?c(A).empty=!1:c(A).unusedTokens.push(e),gA(e,I,A)):A._strict&&!I&&c(A).unusedTokens.push(e);c(A).charsLeftOver=E-N,T.length>0&&c(A).unusedInput.push(T),A._a[gg]<=12&&c(A).bigHour===!0&&A._a[gg]>0&&(c(A).bigHour=void 0),c(A).parsedDateParts=A._a.slice(0),c(A).meridiem=A._meridiem,A._a[gg]=CM(A._locale,A._a[gg],A._meridiem),NM(A),gM(A)}function CM(A,M,t){var I;return null==t?M:null!=A.meridiemHour?A.meridiemHour(M,t):null!=A.isPM?(I=A.isPM(t),I&&M<12&&(M+=12),I||12!==M||(M=0),M):M}function cM(A){var M,t,I,g,e;if(0===A._f.length)return c(A).invalidFormat=!0,void(A._d=new Date(NaN));for(g=0;gthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function fM(){if(!B(this._isDSTShifted))return this._isDSTShifted;var A={};if(Q(A,this),A=BM(A),A._a){var M=A._isUTC?n(A._a):sM(A._a);this._isDSTShifted=this.isValid()&&y(A._a,M.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function kM(){return!!this.isValid()&&!this._isUTC}function RM(){return!!this.isValid()&&this._isUTC}function JM(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function GM(A,M){var t,I,g,e=A,T=null;return wM(A)?e={ms:A._milliseconds,d:A._days,M:A._months}:i(A)?(e={},M?e[M]=A:e.milliseconds=A):(T=Jg.exec(A))?(t="-"===T[1]?-1:1,e={y:0,d:j(T[Ig])*t,h:j(T[gg])*t,m:j(T[eg])*t,s:j(T[ig])*t,ms:j(LM(1e3*T[Tg]))*t}):(T=Gg.exec(A))?(t="-"===T[1]?-1:1,e={y:HM(T[2],t),M:HM(T[3],t),w:HM(T[4],t),d:HM(T[5],t),h:HM(T[6],t),m:HM(T[7],t),s:HM(T[8],t)}):null==e?e={}:"object"==typeof e&&("from"in e||"to"in e)&&(g=XM(sM(e.from),sM(e.to)),e={},e.ms=g.milliseconds,e.M=g.months),I=new uM(e),wM(A)&&N(A,"_locale")&&(I._locale=A._locale),I}function HM(A,M){var t=A&&parseFloat(A.replace(",","."));return(isNaN(t)?0:t)*M}function bM(A,M){var t={milliseconds:0,months:0};return t.months=M.month()-A.month()+12*(M.year()-A.year()),A.clone().add(t.months,"M").isAfter(M)&&--t.months,t.milliseconds=+M-+A.clone().add(t.months,"M"),t}function XM(A,M){var t;return A.isValid()&&M.isValid()?(M=dM(M,A),A.isBefore(M)?t=bM(A,M):(t=bM(M,A),t.milliseconds=-t.milliseconds,t.months=-t.months),t):{milliseconds:0,months:0}}function vM(A,M){return function(t,I){var g,e;return null===I||isNaN(+I)||(L(M,"moment()."+M+"(period, number) is deprecated. Please use moment()."+M+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),e=t,t=I,I=e),t="string"==typeof t?+t:t,g=GM(t,I),WM(this,g,A),this}}function WM(A,t,I,g){var e=t._milliseconds,i=LM(t._days),T=LM(t._months);A.isValid()&&(g=null==g||g,e&&A._d.setTime(A._d.valueOf()+e*I),i&&b(A,"Date",H(A,"Date")+i*I),T&&oA(A,H(A,"Month")+T*I),g&&M.updateOffset(A,i||T))}function VM(A,M){var t=A.diff(M,"days",!0);return t<-6?"sameElse":t<-1?"lastWeek":t<0?"lastDay":t<1?"sameDay":t<2?"nextDay":t<7?"nextWeek":"sameElse"}function PM(A,t){var I=A||sM(),g=dM(I,this).startOf("day"),e=M.calendarFormat(this,g)||"sameElse",i=t&&(l(t[e])?t[e].call(this,I):t[e]);return this.format(i||this.localeData().calendar(e,this,sM(I)))}function ZM(){return new r(this)}function KM(A,M){var t=s(A)?A:sM(A);return!(!this.isValid()||!t.isValid())&&(M=f(B(M)?"millisecond":M),"millisecond"===M?this.valueOf()>t.valueOf():t.valueOf()e&&(M=e),pt.call(this,A,M,t,I,g))}function pt(A,M,t,I,g){var e=yA(A,M,t,I,g),i=xA(e.year,0,e.dayOfYear);return this.year(i.getUTCFullYear()),this.month(i.getUTCMonth()),this.date(i.getUTCDate()),this}function Ut(A){return null==A?Math.ceil((this.month()+1)/3):this.month(3*(A-1)+this.month()%3)}function Ot(A){var M=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==A?M:this.add(A-M,"d")}function mt(A,M){M[Tg]=j(1e3*("0."+A))}function Ft(){return this._isUTC?"UTC":""}function ft(){return this._isUTC?"Coordinated Universal Time":""}function kt(A){return sM(1e3*A)}function Rt(){return sM.apply(null,arguments).parseZone()}function Jt(A){return A}function Gt(A,M,t,I){var g=tM(),e=n().set(I,M);return g[t](e,A)}function Ht(A,M,t){if(i(A)&&(M=A,A=void 0),A=A||"",null!=M)return Gt(A,M,t,"month");var I,g=[];for(I=0;I<12;I++)g[I]=Gt(A,I,t,"month");return g}function bt(A,M,t,I){"boolean"==typeof A?(i(M)&&(t=M,M=void 0),M=M||""):(M=A,t=M,A=!1,i(M)&&(t=M,M=void 0),M=M||"");var g=tM(),e=A?g._week.dow:0;if(null!=t)return Gt(M,(t+e)%7,I,"day");var T,E=[];for(T=0;T<7;T++)E[T]=Gt(M,(T+e)%7,I,"day");return E}function Xt(A,M){return Ht(A,M,"months")}function vt(A,M){return Ht(A,M,"monthsShort")}function Wt(A,M,t){return bt(A,M,t,"weekdays")}function Vt(A,M,t){return bt(A,M,t,"weekdaysShort")}function Pt(A,M,t){return bt(A,M,t,"weekdaysMin")}function Zt(){var A=this._data;return this._milliseconds=_g(this._milliseconds),this._days=_g(this._days),this._months=_g(this._months),A.milliseconds=_g(A.milliseconds),A.seconds=_g(A.seconds),A.minutes=_g(A.minutes),A.hours=_g(A.hours),A.months=_g(A.months),A.years=_g(A.years),this}function Kt(A,M,t,I){var g=GM(M,t);return A._milliseconds+=I*g._milliseconds,A._days+=I*g._days,A._months+=I*g._months,A._bubble()}function qt(A,M){return Kt(this,A,M,1)}function _t(A,M){return Kt(this,A,M,-1)}function $t(A){return A<0?Math.floor(A):Math.ceil(A)}function AI(){var A,M,t,I,g,e=this._milliseconds,i=this._days,T=this._months,E=this._data;return e>=0&&i>=0&&T>=0||e<=0&&i<=0&&T<=0||(e+=864e5*$t(tI(T)+i),i=0,T=0),E.milliseconds=e%1e3,A=x(e/1e3),E.seconds=A%60,M=x(A/60),E.minutes=M%60,t=x(M/60),E.hours=t%24,i+=x(t/24),g=x(MI(i)),T+=g,i-=$t(tI(g)),I=x(T/12),T%=12,E.days=i,E.months=T,E.years=I,this}function MI(A){return 4800*A/146097}function tI(A){return 146097*A/4800}function II(A){var M,t,I=this._milliseconds;if(A=f(A),"month"===A||"year"===A)return M=this._days+I/864e5,t=this._months+MI(M),"month"===A?t:t/12;switch(M=this._days+Math.round(tI(this._months)),A){case"week":return M/7+I/6048e5;case"day":return M+I/864e5;case"hour":return 24*M+I/36e5;case"minute":return 1440*M+I/6e4;case"second":return 86400*M+I/1e3;case"millisecond":return Math.floor(864e5*M)+I;default:throw new Error("Unknown unit "+A)}}function gI(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*j(this._months/12)}function eI(A){return function(){return this.as(A)}}function iI(A){return A=f(A),this[A+"s"]()}function TI(A){return function(){return this._data[A]}}function EI(){return x(this.days()/7)}function NI(A,M,t,I,g){return g.relativeTime(M||1,!!t,A,I)}function oI(A,M,t){var I=GM(A).abs(),g=De(I.as("s")),e=De(I.as("m")),i=De(I.as("h")),T=De(I.as("d")),E=De(I.as("M")),N=De(I.as("y")),o=g0,o[4]=t,NI.apply(null,o)}function nI(A){return void 0===A?De:"function"==typeof A&&(De=A,!0)}function CI(A,M){return void 0!==ae[A]&&(void 0===M?ae[A]:(ae[A]=M,!0))}function cI(A){var M=this.localeData(),t=oI(this,!A,M);return A&&(t=M.pastFuture(+this,t)),M.postformat(t)}function DI(){var A,M,t,I=Be(this._milliseconds)/1e3,g=Be(this._days),e=Be(this._months);A=x(I/60),M=x(A/60),I%=60,A%=60,t=x(e/12),e%=12;var i=t,T=e,E=g,N=M,o=A,n=I,C=this.asSeconds();return C?(C<0?"-":"")+"P"+(i?i+"Y":"")+(T?T+"M":"")+(E?E+"D":"")+(N||o||n?"T":"")+(N?N+"H":"")+(o?o+"M":"")+(n?n+"S":""):"P0D"}var aI,BI;BI=Array.prototype.some?Array.prototype.some:function(A){for(var M=Object(this),t=M.length>>>0,I=0;I68?1900:2e3)};var Bg=G("FullYear",!0);V("w",["ww",2],"wo","week"),V("W",["WW",2],"Wo","isoWeek"),F("week","w"),F("isoWeek","W"),R("week",5),R("isoWeek",5),_("w",GI),_("ww",GI,fI),_("W",GI),_("WW",GI,fI),IA(["w","ww","W","WW"],function(A,M,t,I){M[I.substr(0,1)]=j(A)});var Qg={dow:0,doy:6};V("d",0,"do","day"),V("dd",0,0,function(A){return this.localeData().weekdaysMin(this,A)}),V("ddd",0,0,function(A){return this.localeData().weekdaysShort(this,A)}),V("dddd",0,0,function(A){return this.localeData().weekdays(this,A)}),V("e",0,0,"weekday"),V("E",0,0,"isoWeekday"),F("day","d"),F("weekday","e"),F("isoWeekday","E"),R("day",11),R("weekday",11),R("isoWeekday",11),_("d",GI),_("e",GI),_("E",GI),_("dd",function(A,M){return M.weekdaysMinRegex(A)}),_("ddd",function(A,M){return M.weekdaysShortRegex(A)}),_("dddd",function(A,M){return M.weekdaysRegex(A)}),IA(["dd","ddd","dddd"],function(A,M,t,I){var g=t._locale.weekdaysParse(A,I,t._strict);null!=g?M.d=g:c(t).invalidWeekday=A}),IA(["d","e","E"],function(A,M,t,I){M[I]=j(A)});var rg="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),sg="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),xg="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),jg=_I,yg=_I,ug=_I;V("H",["HH",2],0,"hour"),V("h",["hh",2],0,XA),V("k",["kk",2],0,vA),V("hmm",0,0,function(){return""+XA.apply(this)+W(this.minutes(),2)}),V("hmmss",0,0,function(){return""+XA.apply(this)+W(this.minutes(),2)+W(this.seconds(),2)}),V("Hmm",0,0,function(){return""+this.hours()+W(this.minutes(),2)}),V("Hmmss",0,0,function(){return""+this.hours()+W(this.minutes(),2)+W(this.seconds(),2)}),WA("a",!0),WA("A",!1),F("hour","h"),R("hour",13),_("a",VA),_("A",VA),_("H",GI),_("h",GI),_("HH",GI,fI),_("hh",GI,fI),_("hmm",HI),_("hmmss",bI),_("Hmm",HI),_("Hmmss",bI),tA(["H","HH"],gg),tA(["a","A"],function(A,M,t){t._isPm=t._locale.isPM(A),t._meridiem=A}),tA(["h","hh"],function(A,M,t){M[gg]=j(A),c(t).bigHour=!0}),tA("hmm",function(A,M,t){var I=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I)),c(t).bigHour=!0}),tA("hmmss",function(A,M,t){var I=A.length-4,g=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I,2)),M[ig]=j(A.substr(g)),c(t).bigHour=!0}),tA("Hmm",function(A,M,t){var I=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I))}),tA("Hmmss",function(A,M,t){var I=A.length-4,g=A.length-2;M[gg]=j(A.substr(0,I)),M[eg]=j(A.substr(I,2)),M[ig]=j(A.substr(g))});var wg,Lg=/[ap]\.?m?\.?/i,lg=G("Hours",!0),Yg={calendar:wI,longDateFormat:LI,invalidDate:lI,ordinal:YI,ordinalParse:dI,relativeTime:hI,months:Cg,monthsShort:cg,week:Qg,weekdays:rg,weekdaysMin:xg,weekdaysShort:sg,meridiemParse:Lg},dg={},hg={},Sg=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,zg=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,pg=/Z|[+-]\d\d(?::?\d\d)?/,Ug=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Og=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],mg=/^\/?Date\((\-?\d+)/i;M.createFromInputFallback=w("value provided is not in a recognized ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(A){A._d=new Date(A._i+(A._useUTC?" UTC":""))}),M.ISO_8601=function(){};var Fg=w("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var A=sM.apply(null,arguments);return this.isValid()&&A.isValid()?Athis?this:A:a()}),kg=function(){return Date.now?Date.now():+new Date};lM("Z",":"),lM("ZZ",""),_("Z",KI),_("ZZ",KI),tA(["Z","ZZ"],function(A,M,t){t._useUTC=!0,t._tzm=YM(KI,A)});var Rg=/([\+\-]|\d\d)/gi;M.updateOffset=function(){};var Jg=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Gg=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;GM.fn=uM.prototype;var Hg=vM(1,"add"),bg=vM(-1,"subtract");M.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",M.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Xg=w("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(A){return void 0===A?this.localeData():this.locale(A)});V(0,["gg",2],0,function(){return this.weekYear()%100}),V(0,["GG",2],0,function(){return this.isoWeekYear()%100}),lt("gggg","weekYear"),lt("ggggg","weekYear"),lt("GGGG","isoWeekYear"),lt("GGGGG","isoWeekYear"),F("weekYear","gg"),F("isoWeekYear","GG"),R("weekYear",1),R("isoWeekYear",1),_("G",PI),_("g",PI),_("GG",GI,fI),_("gg",GI,fI),_("GGGG",vI,RI),_("gggg",vI,RI),_("GGGGG",WI,JI),_("ggggg",WI,JI),IA(["gggg","ggggg","GGGG","GGGGG"],function(A,M,t,I){M[I.substr(0,2)]=j(A)}),IA(["gg","GG"],function(A,t,I,g){t[g]=M.parseTwoDigitYear(A)}),V("Q",0,"Qo","quarter"),F("quarter","Q"),R("quarter",7),_("Q",FI),tA("Q",function(A,M){M[tg]=3*(j(A)-1)}),V("D",["DD",2],"Do","date"),F("date","D"),R("date",9),_("D",GI),_("DD",GI,fI),_("Do",function(A,M){return A?M._ordinalParse:M._ordinalParseLenient}),tA(["D","DD"],Ig),tA("Do",function(A,M){M[Ig]=j(A.match(GI)[0],10)});var vg=G("Date",!0);V("DDD",["DDDD",3],"DDDo","dayOfYear"),F("dayOfYear","DDD"),R("dayOfYear",4),_("DDD",XI),_("DDDD",kI),tA(["DDD","DDDD"],function(A,M,t){t._dayOfYear=j(A)}),V("m",["mm",2],0,"minute"),F("minute","m"),R("minute",14),_("m",GI),_("mm",GI,fI),tA(["m","mm"],eg);var Wg=G("Minutes",!1);V("s",["ss",2],0,"second"),F("second","s"),R("second",15),_("s",GI),_("ss",GI,fI),tA(["s","ss"],ig);var Vg=G("Seconds",!1);V("S",0,0,function(){return~~(this.millisecond()/100)}),V(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),V(0,["SSS",3],0,"millisecond"),V(0,["SSSS",4],0,function(){return 10*this.millisecond()}),V(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),V(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),V(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),V(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),V(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),F("millisecond","ms"),R("millisecond",16),_("S",XI,FI),_("SS",XI,fI),_("SSS",XI,kI);var Pg;for(Pg="SSSS";Pg.length<=9;Pg+="S")_(Pg,VI);for(Pg="S";Pg.length<=9;Pg+="S")tA(Pg,mt);var Zg=G("Milliseconds",!1);V("z",0,0,"zoneAbbr"),V("zz",0,0,"zoneName");var Kg=r.prototype;Kg.add=Hg,Kg.calendar=PM,Kg.clone=ZM,Kg.diff=tt,Kg.endOf=at,Kg.format=Tt,Kg.from=Et,Kg.fromNow=Nt,Kg.to=ot,Kg.toNow=nt,Kg.get=X,Kg.invalidAt=wt,Kg.isAfter=KM,Kg.isBefore=qM,Kg.isBetween=_M,Kg.isSame=$M,Kg.isSameOrAfter=At,Kg.isSameOrBefore=Mt,Kg.isValid=yt,Kg.lang=Xg,Kg.locale=Ct,Kg.localeData=ct,Kg.max=fg,Kg.min=Fg,Kg.parsingFlags=ut,Kg.set=v,Kg.startOf=Dt,Kg.subtract=bg,Kg.toArray=st,Kg.toObject=xt,Kg.toDate=rt,Kg.toISOString=et,Kg.inspect=it,Kg.toJSON=jt,Kg.toString=gt,Kg.unix=Qt,Kg.valueOf=Bt,Kg.creationData=Lt,Kg.year=Bg,Kg.isLeapYear=rA,Kg.weekYear=Yt,Kg.isoWeekYear=dt,Kg.quarter=Kg.quarters=Ut,Kg.month=nA,Kg.daysInMonth=CA,Kg.week=Kg.weeks=dA,Kg.isoWeek=Kg.isoWeeks=hA,Kg.weeksInYear=St,Kg.isoWeeksInYear=ht,Kg.date=vg,Kg.day=Kg.days=fA,Kg.weekday=kA,Kg.isoWeekday=RA,Kg.dayOfYear=Ot,Kg.hour=Kg.hours=lg,Kg.minute=Kg.minutes=Wg,Kg.second=Kg.seconds=Vg,Kg.millisecond=Kg.milliseconds=Zg,Kg.utcOffset=SM,Kg.utc=pM,Kg.local=UM,Kg.parseZone=OM,Kg.hasAlignedHourOffset=mM,Kg.isDST=FM,Kg.isLocal=kM,Kg.isUtcOffset=RM,Kg.isUtc=JM,Kg.isUTC=JM,Kg.zoneAbbr=Ft,Kg.zoneName=ft,Kg.dates=w("dates accessor is deprecated. Use date instead.",vg),Kg.months=w("months accessor is deprecated. Use month instead",nA),Kg.years=w("years accessor is deprecated. Use year instead",Bg),Kg.zone=w("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",zM),Kg.isDSTShifted=w("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",fM);var qg=h.prototype;qg.calendar=S,qg.longDateFormat=z,qg.invalidDate=p,qg.ordinal=U,qg.preparse=Jt,qg.postformat=Jt,qg.relativeTime=O,qg.pastFuture=m,qg.set=Y,qg.months=iA,qg.monthsShort=TA,qg.monthsParse=NA,qg.monthsRegex=DA,qg.monthsShortRegex=cA,qg.week=LA,qg.firstDayOfYear=YA,qg.firstDayOfWeek=lA,qg.weekdays=pA,qg.weekdaysMin=OA,qg.weekdaysShort=UA,qg.weekdaysParse=FA,qg.weekdaysRegex=JA,qg.weekdaysShortRegex=GA,qg.weekdaysMinRegex=HA,qg.isPM=PA,qg.meridiem=ZA,$A("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(A){var M=A%10,t=1===j(A%100/10)?"th":1===M?"st":2===M?"nd":3===M?"rd":"th";return A+t}}),M.lang=w("moment.lang is deprecated. Use moment.locale instead.",$A),M.langData=w("moment.langData is deprecated. Use moment.localeData instead.",tM);var _g=Math.abs,$g=eI("ms"),Ae=eI("s"),Me=eI("m"),te=eI("h"),Ie=eI("d"),ge=eI("w"),ee=eI("M"),ie=eI("y"),Te=TI("milliseconds"),Ee=TI("seconds"),Ne=TI("minutes"),oe=TI("hours"),ne=TI("days"),Ce=TI("months"),ce=TI("years"),De=Math.round,ae={s:45,m:45,h:22,d:26,M:11},Be=Math.abs,Qe=uM.prototype;return Qe.abs=Zt,Qe.add=qt,Qe.subtract=_t,Qe.as=II,Qe.asMilliseconds=$g,Qe.asSeconds=Ae,Qe.asMinutes=Me,Qe.asHours=te,Qe.asDays=Ie,Qe.asWeeks=ge,Qe.asMonths=ee,Qe.asYears=ie,Qe.valueOf=gI,Qe._bubble=AI,Qe.get=iI,Qe.milliseconds=Te,Qe.seconds=Ee,Qe.minutes=Ne,Qe.hours=oe,Qe.days=ne,Qe.weeks=EI,Qe.months=Ce,Qe.years=ce,Qe.humanize=cI,Qe.toISOString=DI,Qe.toString=DI,Qe.toJSON=DI,Qe.locale=Ct,Qe.localeData=ct,Qe.toIsoString=w("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",DI),Qe.lang=Xg,V("X",0,0,"unix"),V("x",0,0,"valueOf"),_("x",PI),_("X",qI),tA("X",function(A,M,t){t._d=new Date(1e3*parseFloat(A,10))}),tA("x",function(A,M,t){t._d=new Date(j(A))}),M.version="2.17.1",t(sM),M.fn=Kg,M.min=jM,M.max=yM,M.now=kg,M.utc=n,M.unix=kt,M.months=Xt,M.isDate=T,M.locale=$A,M.invalid=a,M.duration=GM,M.isMoment=s,M.weekdays=Wt,M.parseZone=Rt,M.localeData=tM,M.isDuration=wM,M.monthsShort=vt,M.weekdaysMin=Pt,M.defineLocale=AM,M.updateLocale=MM,M.locales=IM,M.weekdaysShort=Vt,M.normalizeUnits=f,M.relativeTimeRounding=nI,M.relativeTimeThreshold=CI,M.calendarFormat=VM,M.prototype=Kg,M})}).call(M,t(128)(A))},function(A,M,t){"use strict";var I=t(132).default,g=t(133).default,e=t(78).default;M.__esModule=!0;var i=function(A){return I(g({values:function(){var A=this;return e(this).map(function(M){return A[M]})}}),A)},T={SIZES:{large:"lg",medium:"md",small:"sm",xsmall:"xs",lg:"lg",md:"md",sm:"sm",xs:"xs"},GRID_COLUMNS:12},E=i({LARGE:"large",MEDIUM:"medium",SMALL:"small",XSMALL:"xsmall"});M.Sizes=E;var N=i({SUCCESS:"success",WARNING:"warning",DANGER:"danger",INFO:"info"});M.State=N;var o="default";M.DEFAULT=o;var n="primary";M.PRIMARY=n;var C="link";M.LINK=C;var c="inverse";M.INVERSE=c,M.default=T},function(A,M){"use strict";function t(){for(var A=arguments.length,M=Array(A),t=0;t0?void 0:(0,C.default)(!1),null!=o&&(e+=encodeURI(o))):"("===E?g+=1:")"===E?g-=1:":"===E.charAt(0)?(N=E.substring(1),o=M[N],null!=o||g>0?void 0:(0,C.default)(!1),null!=o&&(e+=encodeURIComponent(o))):e+=E;return e.replace(/\/+/g,"/")}M.__esModule=!0,M.compilePattern=i,M.matchPattern=T,M.getParamNames=E,M.getParams=N,M.formatPattern=o;var n=t(8),C=I(n),c=Object.create(null)},function(A,M){"use strict";M.__esModule=!0;var t="PUSH";M.PUSH=t;var I="REPLACE";M.REPLACE=I;var g="POP";M.POP=g,M.default={PUSH:t,REPLACE:I,POP:g}},function(A,M,t){"use strict";function I(A,M){return(A&M)===M}var g=t(2),e={MUST_USE_ATTRIBUTE:1,MUST_USE_PROPERTY:2,HAS_SIDE_EFFECTS:4,HAS_BOOLEAN_VALUE:8,HAS_NUMERIC_VALUE:16,HAS_POSITIVE_NUMERIC_VALUE:48,HAS_OVERLOADED_BOOLEAN_VALUE:64,injectDOMPropertyConfig:function(A){var M=e,t=A.Properties||{},i=A.DOMAttributeNamespaces||{},E=A.DOMAttributeNames||{},N=A.DOMPropertyNames||{},o=A.DOMMutationMethods||{};A.isCustomAttribute&&T._isCustomAttributeFunctions.push(A.isCustomAttribute);for(var n in t){T.properties.hasOwnProperty(n)?g(!1):void 0;var C=n.toLowerCase(),c=t[n],D={attributeName:C,attributeNamespace:null,propertyName:n,mutationMethod:null,mustUseAttribute:I(c,M.MUST_USE_ATTRIBUTE),mustUseProperty:I(c,M.MUST_USE_PROPERTY),hasSideEffects:I(c,M.HAS_SIDE_EFFECTS),hasBooleanValue:I(c,M.HAS_BOOLEAN_VALUE),hasNumericValue:I(c,M.HAS_NUMERIC_VALUE),hasPositiveNumericValue:I(c,M.HAS_POSITIVE_NUMERIC_VALUE),hasOverloadedBooleanValue:I(c,M.HAS_OVERLOADED_BOOLEAN_VALUE)};if(D.mustUseAttribute&&D.mustUseProperty?g(!1):void 0,!D.mustUseProperty&&D.hasSideEffects?g(!1):void 0,D.hasBooleanValue+D.hasNumericValue+D.hasOverloadedBooleanValue<=1?void 0:g(!1),E.hasOwnProperty(n)){var a=E[n];D.attributeName=a}i.hasOwnProperty(n)&&(D.attributeNamespace=i[n]),N.hasOwnProperty(n)&&(D.propertyName=N[n]),o.hasOwnProperty(n)&&(D.mutationMethod=o[n]),T.properties[n]=D}}},i={},T={ID_ATTRIBUTE_NAME:"data-reactid",properties:{},getPossibleStandardName:null,_isCustomAttributeFunctions:[],isCustomAttribute:function(A){for(var M=0;M1){var M=A.indexOf(c,1);return M>-1?A.substr(0,M):A}return null},traverseEnterLeave:function(A,M,t,I,g){var e=N(A,M);e!==A&&o(A,e,t,I,!1,!0),e!==M&&o(e,M,t,g,!0,!1)},traverseTwoPhase:function(A,M,t){A&&(o("",A,M,t,!0,!1),o(A,"",M,t,!1,!0))},traverseTwoPhaseSkipTarget:function(A,M,t){A&&(o("",A,M,t,!0,!0),o(A,"",M,t,!0,!0))},traverseAncestors:function(A,M,t){o("",A,M,t,!0,!1)},getFirstCommonAncestorID:N,_getNextDescendantID:E,isAncestorIDOf:i,SEPARATOR:c};A.exports=B},function(A,M){var t=A.exports={version:"1.2.6"};"number"==typeof __e&&(__e=t)},function(A,M,t){"use strict";var I={};A.exports=I},function(A,M,t){"use strict";function I(A,M,t){var I=0;return n.default.Children.map(A,function(A){if(n.default.isValidElement(A)){var g=I;return I++,M.call(t,A,g)}return A})}function g(A,M,t){var I=0;return n.default.Children.forEach(A,function(A){n.default.isValidElement(A)&&(M.call(t,A,I),I++)})}function e(A){var M=0;return n.default.Children.forEach(A,function(A){n.default.isValidElement(A)&&M++}),M}function i(A){var M=!1;return n.default.Children.forEach(A,function(A){!M&&n.default.isValidElement(A)&&(M=!0)}),M}function T(A,M){var t=void 0;return g(A,function(I,g){!t&&M(I,g,A)&&(t=I)}),t}function E(A,M,t){var I=0,g=[];return n.default.Children.forEach(A,function(A){n.default.isValidElement(A)&&(M.call(t,A,I)&&g.push(A),I++)}),g}var N=t(6).default;M.__esModule=!0;var o=t(1),n=N(o);M.default={map:I,forEach:g,numberOf:e,find:T,findValidComponents:E,hasValidComponent:i},A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0}),M.default=function(A){return(0,T.default)(e.default.findDOMNode(A))};var g=t(16),e=I(g),i=t(39),T=I(i);A.exports=M.default},function(A,M,t){"use strict";var I=t(204),g=t(437),e=t(217),i=t(226),T=t(227),E=t(2),N=(t(3),{}),o=null,n=function(A,M){A&&(g.executeDispatchesInOrder(A,M),A.isPersistent()||A.constructor.release(A))},C=function(A){return n(A,!0)},c=function(A){return n(A,!1)},D=null,a={injection:{injectMount:g.injection.injectMount,injectInstanceHandle:function(A){D=A},getInstanceHandle:function(){return D},injectEventPluginOrder:I.injectEventPluginOrder,injectEventPluginsByName:I.injectEventPluginsByName},eventNameDispatchConfigs:I.eventNameDispatchConfigs,registrationNameModules:I.registrationNameModules,putListener:function(A,M,t){"function"!=typeof t?E(!1):void 0;var g=N[M]||(N[M]={});g[A]=t;var e=I.registrationNameModules[M];e&&e.didPutListener&&e.didPutListener(A,M,t)},getListener:function(A,M){var t=N[M];return t&&t[A]},deleteListener:function(A,M){var t=I.registrationNameModules[M];t&&t.willDeleteListener&&t.willDeleteListener(A,M);var g=N[M];g&&delete g[A]},deleteAllListeners:function(A){for(var M in N)if(N[M][A]){var t=I.registrationNameModules[M];t&&t.willDeleteListener&&t.willDeleteListener(A,M),delete N[M][A]}},extractEvents:function(A,M,t,g,e){for(var T,E=I.plugins,N=0;N1?I-1:0),e=1;e":">","<":"<",'"':""","'":"'"},e=/[&><"']/g;A.exports=I},function(A,M,t){"use strict";var I=t(10),g=/^[ \r\n\t\f]/,e=/<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/,i=function(A,M){A.innerHTML=M};if("undefined"!=typeof MSApp&&MSApp.execUnsafeLocalFunction&&(i=function(A,M){MSApp.execUnsafeLocalFunction(function(){A.innerHTML=M})}),I.canUseDOM){var T=document.createElement("div");T.innerHTML=" ",""===T.innerHTML&&(i=function(A,M){if(A.parentNode&&A.parentNode.replaceChild(A,A),g.test(M)||"<"===M[0]&&e.test(M)){A.innerHTML=String.fromCharCode(65279)+M;var t=A.firstChild;1===t.data.length?A.removeChild(t):t.deleteData(0,1)}else A.innerHTML=M})}A.exports=i},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var g=t(1),e=I(g),i=function(A){var M=A.label,t=A.id,I=A.name,g=A.value,i=A.onChange,T=A.type,E=A.spellCheck,N=A.required,o=A.readonly,n=A.autoComplete,C=A.align,c=A.className,D=e.default.createElement("input",{id:t,name:I,value:g,onChange:i,className:"ig-text",type:T,spellCheck:E,required:N,autoComplete:n});return o&&(D=e.default.createElement("input",{id:t,name:I,value:g,onChange:i,className:"ig-text",type:T,spellCheck:E,required:N,autoComplete:n,disabled:!0})),e.default.createElement("div",{className:"input-group "+C+" "+c},D,e.default.createElement("i",{className:"ig-helpers"}),e.default.createElement("label",{className:"ig-label"},M))};M.default=i},function(A,M,t){A.exports={default:t(259),__esModule:!0}},function(A,M,t){var I=t(265),g=t(49),e=t(134),i="prototype",T=function(A,M,t){var E,N,o,n=A&T.F,C=A&T.G,c=A&T.S,D=A&T.P,a=A&T.B,B=A&T.W,Q=C?g:g[M]||(g[M]={}),r=C?I:c?I[M]:(I[M]||{})[i];C&&(t=M);for(E in t)N=!n&&r&&E in r,N&&E in Q||(o=N?r[E]:t[E],Q[E]=C&&"function"!=typeof r[E]?t[E]:a&&N?e(o,I):B&&r[E]==o?function(A){var M=function(M){return this instanceof A?new A(M):A(M)};return M[i]=A[i],M}(o):D&&"function"==typeof o?e(Function.call,o):o,D&&((Q[i]||(Q[i]={}))[E]=o))};T.F=1,T.G=2,T.S=4,T.P=8,T.B=16,T.W=32,A.exports=T},function(A,M){var t=Object;A.exports={create:t.create,getProto:t.getPrototypeOf,isEnum:{}.propertyIsEnumerable,getDesc:t.getOwnPropertyDescriptor,setDesc:t.defineProperty,setDescs:t.defineProperties,getKeys:t.keys,getNames:t.getOwnPropertyNames,getSymbols:t.getOwnPropertySymbols,each:[].forEach}},function(A,M,t){"use strict";var I=t(32),g=function(){};I&&(g=function(){return document.addEventListener?function(A,M,t,I){return A.addEventListener(M,t,I||!1)}:document.attachEvent?function(A,M,t){return A.attachEvent("on"+M,t)}:void 0}()),A.exports=g},function(A,M,t){"use strict";var I=t(145),g=t(295),e=t(290),i=t(291),T=Object.prototype.hasOwnProperty;A.exports=function(A,M,t){var E="",N=M;if("string"==typeof M){if(void 0===t)return A.style[I(M)]||e(A).getPropertyValue(g(M));(N={})[M]=t}for(var o in N)T.call(N,o)&&(N[o]||0===N[o]?E+=g(o)+":"+N[o]+";":i(A,g(o)));A.style.cssText+=";"+E}},function(A,M,t){(function(){var t=this,I=t.humanize,g={};"undefined"!=typeof A&&A.exports&&(M=A.exports=g),M.humanize=g,g.noConflict=function(){return t.humanize=I,this},g.pad=function(A,M,t,I){if(A+="",t?t.length>1&&(t=t.charAt(0)):t=" ",I=void 0===I?"left":"right","right"===I)for(;A.length4&&A<21?"th":{1:"st",2:"nd",3:"rd"}[A%10]||"th"},w:function(){return t.getDay()},z:function(){return(o.L()?i[o.n()]:e[o.n()])+o.j()-1},W:function(){var A=o.z()-o.N()+1.5;return g.pad(1+Math.floor(Math.abs(A)/7)+(A%7>3.5?1:0),2,"0")},F:function(){return N[t.getMonth()]},m:function(){return g.pad(o.n(),2,"0")},M:function(){return o.F().slice(0,3)},n:function(){return t.getMonth()+1},t:function(){return new Date(o.Y(),o.n(),0).getDate()},L:function(){return 1===new Date(o.Y(),1,29).getMonth()?1:0},o:function(){var A=o.n(),M=o.W();return o.Y()+(12===A&&M<9?-1:1===A&&M>9)},Y:function(){return t.getFullYear()},y:function(){return String(o.Y()).slice(-2)},a:function(){return t.getHours()>11?"pm":"am"},A:function(){return o.a().toUpperCase()},B:function(){var A=t.getTime()/1e3,M=A%86400+3600;M<0&&(M+=86400);var I=M/86.4%1e3;return A<0?Math.ceil(I):Math.floor(I)},g:function(){return o.G()%12||12},G:function(){return t.getHours()},h:function(){return g.pad(o.g(),2,"0")},H:function(){return g.pad(o.G(),2,"0")},i:function(){return g.pad(t.getMinutes(),2,"0")},s:function(){return g.pad(t.getSeconds(),2,"0")},u:function(){return g.pad(1e3*t.getMilliseconds(),6,"0")},O:function(){var A=t.getTimezoneOffset(),M=Math.abs(A);return(A>0?"-":"+")+g.pad(100*Math.floor(M/60)+M%60,4,"0")},P:function(){var A=o.O();return A.substr(0,3)+":"+A.substr(3,2)},Z:function(){return 60*-t.getTimezoneOffset()},c:function(){return"Y-m-d\\TH:i:sP".replace(I,T)},r:function(){return"D, d M Y H:i:s O".replace(I,T)},U:function(){return t.getTime()/1e3||0}};return A.replace(I,T)},g.numberFormat=function(A,M,t,I){M=isNaN(M)?2:Math.abs(M),t=void 0===t?".":t,I=void 0===I?",":I;var g=A<0?"-":"";A=Math.abs(+A||0);var e=parseInt(A.toFixed(M),10)+"",i=e.length>3?e.length%3:0;return g+(i?e.substr(0,i)+I:"")+e.substr(i).replace(/(\d{3})(?=\d)/g,"$1"+I)+(M?t+Math.abs(A-e).toFixed(M).slice(2):"")},g.naturalDay=function(A,M){A=void 0===A?g.time():A,M=void 0===M?"Y-m-d":M;var t=86400,I=new Date,e=new Date(I.getFullYear(),I.getMonth(),I.getDate()).getTime()/1e3;return A=e-t?"yesterday":A>=e&&A=e+t&&A-2)return(t>=0?"just ":"")+"now";if(t<60&&t>-60)return t>=0?Math.floor(t)+" seconds ago":"in "+Math.floor(-t)+" seconds";if(t<120&&t>-120)return t>=0?"about a minute ago":"in about a minute";if(t<3600&&t>-3600)return t>=0?Math.floor(t/60)+" minutes ago":"in "+Math.floor(-t/60)+" minutes";if(t<7200&&t>-7200)return t>=0?"about an hour ago":"in about an hour";if(t<86400&&t>-86400)return t>=0?Math.floor(t/3600)+" hours ago":"in "+Math.floor(-t/3600)+" hours";var I=172800;if(t-I)return t>=0?"1 day ago":"in 1 day";var e=2505600;if(t-e)return t>=0?Math.floor(t/86400)+" days ago":"in "+Math.floor(-t/86400)+" days";var i=5184e3;if(t-i)return t>=0?"about a month ago":"in about a month";var T=parseInt(g.date("Y",M),10),E=parseInt(g.date("Y",A),10),N=12*T+parseInt(g.date("n",M),10),o=12*E+parseInt(g.date("n",A),10),n=N-o;if(n<12&&n>-12)return n>=0?n+" months ago":"in "+-n+" months";var C=T-E;return C<2&&C>-2?C>=0?"a year ago":"in a year":C>=0?C+" years ago":"in "+-C+" years"},g.ordinal=function(A){A=parseInt(A,10),A=isNaN(A)?0:A;var M=A<0?"-":"";A=Math.abs(A);var t=A%100;return M+A+(t>4&&t<21?"th":{1:"st",2:"nd",3:"rd"}[A%10]||"th")},g.filesize=function(A,M,t,I,e,i){return M=void 0===M?1024:M,A<=0?"0 bytes":(A

    "),A=A.replace(/\n/g,"
    "),"

    "+A+"

    "},g.nl2br=function(A){return A.replace(/(\r\n|\n|\r)/g,"
    ")},g.truncatechars=function(A,M){return A.length<=M?A:A.substr(0,M)+"…"},g.truncatewords=function(A,M){var t=A.split(" ");return t.length0,Q=C.enumErrorProps&&(A===u||A instanceof Error),r=C.enumPrototypes&&T(A);++IM.documentElement.clientHeight;return{modalStyles:{paddingRight:I&&!g?Q.default():void 0,paddingLeft:!I&&g?Q.default():void 0}}}});X.Body=z.default,X.Header=U.default,X.Title=m.default,X.Footer=f.default,X.Dialog=h.default,X.TRANSITION_DURATION=300,X.BACKDROP_TRANSITION_DURATION=150,M.default=c.bsSizes([a.Sizes.LARGE,a.Sizes.SMALL],c.bsClass("modal",X)),A.exports=M.default},function(A,M,t){"use strict";var I=t(15).default,g=t(14).default,e=t(38).default,i=t(7).default,T=t(6).default;M.__esModule=!0;var E=t(1),N=T(E),o=t(5),n=T(o),C=t(11),c=T(C),D=t(44),a=T(D),B=function(A){function M(){g(this,M),A.apply(this,arguments)}return I(M,A),M.prototype.render=function(){var A=this.props,M=A["aria-label"],t=e(A,["aria-label"]),I=a.default(this.context.$bs_onModalHide,this.props.onHide);return N.default.createElement("div",i({},t,{className:n.default(this.props.className,c.default.prefix(this.props,"header"))}),this.props.closeButton&&N.default.createElement("button",{type:"button",className:"close","aria-label":M,onClick:I},N.default.createElement("span",{"aria-hidden":"true" +},"×")),this.props.children)},M}(N.default.Component);B.propTypes={"aria-label":N.default.PropTypes.string,bsClass:N.default.PropTypes.string,closeButton:N.default.PropTypes.bool,onHide:N.default.PropTypes.func},B.contextTypes={$bs_onModalHide:N.default.PropTypes.func},B.defaultProps={"aria-label":"Close",closeButton:!1},M.default=C.bsClass("modal",B),A.exports=M.default},function(A,M,t){"use strict";function I(A,M){return Array.isArray(M)?M.indexOf(A)>=0:A===M}var g=t(7).default,e=t(78).default,i=t(6).default;M.__esModule=!0;var T=t(40),E=i(T),N=t(170),o=i(N),n=t(1),C=i(n),c=t(16),D=i(c),a=t(127),B=(i(a),t(370)),Q=i(B),r=t(44),s=i(r),x=C.default.createClass({displayName:"OverlayTrigger",propTypes:g({},Q.default.propTypes,{trigger:C.default.PropTypes.oneOfType([C.default.PropTypes.oneOf(["click","hover","focus"]),C.default.PropTypes.arrayOf(C.default.PropTypes.oneOf(["click","hover","focus"]))]),delay:C.default.PropTypes.number,delayShow:C.default.PropTypes.number,delayHide:C.default.PropTypes.number,defaultOverlayShown:C.default.PropTypes.bool,overlay:C.default.PropTypes.node.isRequired,onBlur:C.default.PropTypes.func,onClick:C.default.PropTypes.func,onFocus:C.default.PropTypes.func,onMouseEnter:C.default.PropTypes.func,onMouseLeave:C.default.PropTypes.func,target:function(){},onHide:function(){},show:function(){}}),getDefaultProps:function(){return{defaultOverlayShown:!1,trigger:["hover","focus"]}},getInitialState:function(){return{isOverlayShown:this.props.defaultOverlayShown}},show:function(){this.setState({isOverlayShown:!0})},hide:function(){this.setState({isOverlayShown:!1})},toggle:function(){this.state.isOverlayShown?this.hide():this.show()},componentWillMount:function(){this.handleMouseOver=this.handleMouseOverOut.bind(null,this.handleDelayedShow),this.handleMouseOut=this.handleMouseOverOut.bind(null,this.handleDelayedHide)},componentDidMount:function(){this._mountNode=document.createElement("div"),this.renderOverlay()},renderOverlay:function(){D.default.unstable_renderSubtreeIntoContainer(this,this._overlay,this._mountNode)},componentWillUnmount:function(){D.default.unmountComponentAtNode(this._mountNode),this._mountNode=null,clearTimeout(this._hoverShowDelay),clearTimeout(this._hoverHideDelay)},componentDidUpdate:function(){this._mountNode&&this.renderOverlay()},getOverlayTarget:function(){return D.default.findDOMNode(this)},getOverlay:function(){var A=g({},o.default(this.props,e(Q.default.propTypes)),{show:this.state.isOverlayShown,onHide:this.hide,target:this.getOverlayTarget,onExit:this.props.onExit,onExiting:this.props.onExiting,onExited:this.props.onExited,onEnter:this.props.onEnter,onEntering:this.props.onEntering,onEntered:this.props.onEntered}),M=n.cloneElement(this.props.overlay,{placement:A.placement,container:A.container});return C.default.createElement(Q.default,A,M)},render:function(){var A=C.default.Children.only(this.props.children),M=A.props,t={"aria-describedby":this.props.overlay.props.id};return this._overlay=this.getOverlay(),t.onClick=s.default(M.onClick,this.props.onClick),I("click",this.props.trigger)&&(t.onClick=s.default(this.toggle,t.onClick)),I("hover",this.props.trigger)&&(t.onMouseOver=s.default(this.handleMouseOver,this.props.onMouseOver,M.onMouseOver),t.onMouseOut=s.default(this.handleMouseOut,this.props.onMouseOut,M.onMouseOut)),I("focus",this.props.trigger)&&(t.onFocus=s.default(this.handleDelayedShow,this.props.onFocus,M.onFocus),t.onBlur=s.default(this.handleDelayedHide,this.props.onBlur,M.onBlur)),n.cloneElement(A,t)},handleDelayedShow:function(){var A=this;if(null!=this._hoverHideDelay)return clearTimeout(this._hoverHideDelay),void(this._hoverHideDelay=null);if(!this.state.isOverlayShown&&null==this._hoverShowDelay){var M=null!=this.props.delayShow?this.props.delayShow:this.props.delay;return M?void(this._hoverShowDelay=setTimeout(function(){A._hoverShowDelay=null,A.show()},M)):void this.show()}},handleDelayedHide:function(){var A=this;if(null!=this._hoverShowDelay)return clearTimeout(this._hoverShowDelay),void(this._hoverShowDelay=null);if(this.state.isOverlayShown&&null==this._hoverHideDelay){var M=null!=this.props.delayHide?this.props.delayHide:this.props.delay;return M?void(this._hoverHideDelay=setTimeout(function(){A._hoverHideDelay=null,A.hide()},M)):void this.hide()}},handleMouseOverOut:function(A,M){var t=M.currentTarget,I=M.relatedTarget||M.nativeEvent.toElement;I&&(I===t||E.default(t,I))||A(M)}});M.default=x,A.exports=M.default},function(A,M,t){"use strict";var I=t(7).default,g=t(6).default;M.__esModule=!0;var e=t(1),i=g(e),T=t(5),E=g(T),N=t(11),o=g(N),n=t(183),C=g(n),c=i.default.createClass({displayName:"Tooltip",propTypes:{id:C.default(i.default.PropTypes.oneOfType([i.default.PropTypes.string,i.default.PropTypes.number])),placement:i.default.PropTypes.oneOf(["top","right","bottom","left"]),positionLeft:i.default.PropTypes.number,positionTop:i.default.PropTypes.number,arrowOffsetLeft:i.default.PropTypes.oneOfType([i.default.PropTypes.number,i.default.PropTypes.string]),arrowOffsetTop:i.default.PropTypes.oneOfType([i.default.PropTypes.number,i.default.PropTypes.string]),title:i.default.PropTypes.node},getDefaultProps:function(){return{bsClass:"tooltip",placement:"right"}},render:function(){var A,M=(A={},A[o.default.prefix(this.props)]=!0,A[this.props.placement]=!0,A),t=I({left:this.props.positionLeft,top:this.props.positionTop},this.props.style),g={left:this.props.arrowOffsetLeft,top:this.props.arrowOffsetTop};return i.default.createElement("div",I({role:"tooltip"},this.props,{className:E.default(this.props.className,M),style:t}),i.default.createElement("div",{className:o.default.prefix(this.props,"arrow"),style:g}),i.default.createElement("div",{className:o.default.prefix(this.props,"inner")},this.props.children))}});M.default=c,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){return A="function"==typeof A?A():A,i.default.findDOMNode(A)||M}Object.defineProperty(M,"__esModule",{value:!0}),M.default=g;var e=t(16),i=I(e);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M,t,I,g){var i=A[M],E="undefined"==typeof i?"undefined":e(i);return T.default.isValidElement(i)?new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of type ReactElement "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected a ReactComponent or a ")+"DOMElement. You can usually obtain a ReactComponent or DOMElement from a ReactElement by attaching a ref to it."):"object"===E&&"function"==typeof i.render||1===i.nodeType?null:new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of value ` + "`" + `"+i+"` + "`" + ` "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected a ReactComponent or a ")+"DOMElement.")}M.__esModule=!0;var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol?"symbol":typeof A},i=t(1),T=I(i),E=t(182),N=I(E);M.default=(0,N.default)(g)},function(A,M,t){"use strict";function I(){function A(A,M,I){for(var g=0;g>",null!=t[I]?A(t,I,g):M?new Error("Required prop '"+I+"' was not specified in '"+g+"'."):void 0}var t=M.bind(null,!1);return t.isRequired=M.bind(null,!0),t}M.__esModule=!0,M.errMsg=t,M.createChainableTypeChecker=I},function(A,M){"use strict";function t(A,M,t){function I(){return i=!0,T?void(N=[].concat(Array.prototype.slice.call(arguments))):void t.apply(this,arguments)}function g(){if(!i&&(E=!0,!T)){for(T=!0;!i&&e=A&&E&&(i=!0,t()))}}var e=0,i=!1,T=!1,E=!1,N=void 0;g()}function I(A,M,t){function I(A,M,I){i||(M?(i=!0,t(M)):(e[A]=I,i=++T===g,i&&t(null,e)))}var g=A.length,e=[];if(0===g)return t(null,e);var i=!1,T=0;A.forEach(function(A,t){M(A,t,function(A,M){I(t,A,M)})})}M.__esModule=!0,M.loopAsync=t,M.mapAsync=I},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}M.__esModule=!0,M.router=M.routes=M.route=M.components=M.component=M.location=M.history=M.falsy=M.locationShape=M.routerShape=void 0;var e=t(1),i=t(66),T=(g(i),t(34)),E=I(T),N=t(9),o=(g(N),e.PropTypes.func),n=e.PropTypes.object,C=e.PropTypes.shape,c=e.PropTypes.string,D=M.routerShape=C({push:o.isRequired,replace:o.isRequired,go:o.isRequired,goBack:o.isRequired,goForward:o.isRequired,setRouteLeaveHook:o.isRequired,isActive:o.isRequired}),a=M.locationShape=C({pathname:c.isRequired,search:c.isRequired,state:n,action:c.isRequired,key:c}),B=M.falsy=E.falsy,Q=M.history=E.history,r=M.location=a,s=M.component=E.component,x=M.components=E.components,j=M.route=E.route,y=(M.routes=E.routes,M.router=D),u={falsy:B,history:Q,location:r,component:s,components:x,route:j,router:y};M.default=u},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A){for(var M in A)if(Object.prototype.hasOwnProperty.call(A,M))return!0;return!1}function e(A,M){function t(M){var t=!(arguments.length<=1||void 0===arguments[1])&&arguments[1],I=arguments.length<=2||void 0===arguments[2]?null:arguments[2],g=void 0;return t&&t!==!0||null!==I?(M={pathname:M,query:t},g=I||!1):(M=A.createLocation(M),g=t),(0,C.default)(M,g,s.location,s.routes,s.params)}function I(A,t){x&&x.location===A?e(x,t):(0,B.default)(M,A,function(M,I){M?t(M):I?e(i({},I,{location:A}),t):t()})}function e(A,M){function t(t,g){return t||g?I(t,g):void(0,D.default)(A,function(t,I){t?M(t):M(null,null,s=i({},A,{components:I}))})}function I(A,t){A?M(A):M(null,t)}var g=(0,N.default)(s,A),e=g.leaveRoutes,T=g.changeRoutes,E=g.enterRoutes;(0,o.runLeaveHooks)(e,s),e.filter(function(A){return E.indexOf(A)===-1}).forEach(a),(0,o.runChangeHooks)(T,s,A,function(M,g){return M||g?I(M,g):void(0,o.runEnterHooks)(E,A,t)})}function T(A){var M=arguments.length<=1||void 0===arguments[1]||arguments[1];return A.__id__||M&&(A.__id__=j++)}function E(A){return A.reduce(function(A,M){return A.push.apply(A,y[T(M)]),A},[])}function n(A,t){(0,B.default)(M,A,function(M,I){if(null==I)return void t();x=i({},I,{location:A});for(var g=E((0,N.default)(s,x).leaveRoutes),e=void 0,T=0,o=g.length;null==e&&T=32||13===M?M:0}A.exports=t},function(A,M){"use strict";function t(A){var M=this,t=M.nativeEvent;if(t.getModifierState)return t.getModifierState(A);var I=g[A];return!!I&&!!t[I]}function I(A){return t}var g={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"};A.exports=I},function(A,M){"use strict";function t(A){var M=A.target||A.srcElement||window;return 3===M.nodeType?M.parentNode:M}A.exports=t},function(A,M){"use strict";function t(A){var M=A&&(I&&A[I]||A[g]);if("function"==typeof M)return M}var I="function"==typeof Symbol&&Symbol.iterator,g="@@iterator";A.exports=t},function(A,M,t){"use strict";function I(A){return"function"==typeof A&&"undefined"!=typeof A.prototype&&"function"==typeof A.prototype.mountComponent&&"function"==typeof A.prototype.receiveComponent}function g(A){var M;if(null===A||A===!1)M=new i(g);else if("object"==typeof A){var t=A;!t||"function"!=typeof t.type&&"string"!=typeof t.type?N(!1):void 0,M="string"==typeof t.type?T.createInternalComponent(t):I(t.type)?new t.type(t):new o}else"string"==typeof A||"number"==typeof A?M=T.createInstanceForText(A):N(!1);return M.construct(A),M._mountIndex=0,M._mountImage=null,M}var e=t(443),i=t(215),T=t(221),E=t(4),N=t(2),o=(t(3),function(){});E(o.prototype,e.Mixin,{_instantiateReactComponent:g}),A.exports=g},function(A,M,t){"use strict";/** * Checks if an event is supported in the current execution environment. * * NOTE: This will not work correctly for non-generic events such as ` + "`" + `change` + "`" + `, @@ -200,21 +200,21 @@ propTypes:g({},Q.default.propTypes,{trigger:C.default.PropTypes.oneOfType([C.def * @internal * @license Modernizr 3.0.0pre (Custom Build) | MIT */ -function I(A,M){if(!e.canUseDOM||M&&!("addEventListener"in document))return!1;var t="on"+A,I=t in document;if(!I){var i=document.createElement("div");i.setAttribute(t,"return;"),I="function"==typeof i[t]}return!I&&g&&"wheel"===A&&(I=document.implementation.hasFeature("Events.wheel","3.0")),I}var g,e=t(10);e.canUseDOM&&(g=document.implementation&&document.implementation.hasFeature&&document.implementation.hasFeature("","")!==!0),A.exports=I},function(A,M,t){"use strict";var I=t(10),g=t(75),e=t(76),i=function(A,M){A.textContent=M};I.canUseDOM&&("textContent"in document.documentElement||(i=function(A,M){e(A,g(M))})),A.exports=i},function(A,M){"use strict";function t(A,M){var t=null===A||A===!1,I=null===M||M===!1;if(t||I)return t===I;var g=typeof A,e=typeof M;return"string"===g||"number"===g?"string"===e||"number"===e:"object"===e&&A.type===M.type&&A.key===M.key}A.exports=t},function(A,M,t){"use strict";function I(A){return a[A]}function g(A,M){return A&&null!=A.key?i(A.key):M.toString(36)}function e(A){return(""+A).replace(B,I)}function i(A){return"$"+e(A)}function T(A,M,t,I){var e=typeof A;if("undefined"!==e&&"boolean"!==e||(A=null),null===A||"string"===e||"number"===e||N.isValidElement(A))return t(I,A,""===M?c+g(A,0):M),1;var E,o,a=0,B=""===M?c:M+D;if(Array.isArray(A))for(var Q=0;QM.name.toLowerCase()?1:0}),g=g.sort(function(A,M){return A.name.toLowerCase()M.name.toLowerCase()?1:0}),M&&(t=t.reverse(),g=g.reverse()),[].concat(I(t),I(g))},M.sortObjectsBySize=function(A,M){var t=A.filter(function(A){return A.name.endsWith("/")}),g=A.filter(function(A){return!A.name.endsWith("/")});return g=g.sort(function(A,M){return A.size-M.size}),M&&(g=g.reverse()),[].concat(I(t),I(g))},M.sortObjectsByDate=function(A,M){var t=A.filter(function(A){return A.name.endsWith("/")}),g=A.filter(function(A){return!A.name.endsWith("/")});return g=g.sort(function(A,M){return new Date(A.lastModified).getTime()-new Date(M.lastModified).getTime()}),M&&(g=g.reverse()),[].concat(I(t),I(g))},M.pathSlice=function(A){A=A.replace(g.minioBrowserPrefix,"");var M="",t="";if(!A)return{bucket:t,prefix:M};var I=A.indexOf("/",1);return I==-1?(t=A.slice(1),{bucket:t,prefix:M}):(t=A.slice(1,I),M=A.slice(I+1),{bucket:t,prefix:M})},M.pathJoin=function(A,M){return M||(M=""),g.minioBrowserPrefix+"/"+A+"/"+M}},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(M,"__esModule",{value:!0});var i=function(){function A(A,M){for(var t=0;t":i.innerHTML="<"+A+">",T[A]=!i.firstChild),T[A]?C[A]:null}var g=t(10),e=t(2),i=g.canUseDOM?document.createElement("div"):null,T={},E=[1,'"],N=[1,"","
    "],o=[3,"","
    "],n=[1,'',""],C={"*":[1,"?
    ","
    "],area:[1,"",""],col:[2,"","
    "],legend:[1,"
    ","
    "],param:[1,"",""],tr:[2,"","
    "],optgroup:E,option:E,caption:N,colgroup:N,tbody:N,tfoot:N,thead:N,td:o,th:o},c=["circle","clipPath","defs","ellipse","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan"];c.forEach(function(A){C[A]=n,T[A]=!0}),A.exports=I},function(A,M){"use strict";function t(A,M){if(A===M)return!0;if("object"!=typeof A||null===A||"object"!=typeof M||null===M)return!1;var t=Object.keys(A),g=Object.keys(M);if(t.length!==g.length)return!1;for(var e=I.bind(M),i=0;iM.name.toLowerCase()?1:0}),g=g.sort(function(A,M){return A.name.toLowerCase()M.name.toLowerCase()?1:0}),M&&(t=t.reverse(),g=g.reverse()),[].concat(I(t),I(g))},M.sortObjectsBySize=function(A,M){var t=A.filter(function(A){return A.name.endsWith("/")}),g=A.filter(function(A){return!A.name.endsWith("/")});return g=g.sort(function(A,M){return A.size-M.size}),M&&(g=g.reverse()),[].concat(I(t),I(g))},M.sortObjectsByDate=function(A,M){var t=A.filter(function(A){return A.name.endsWith("/")}),g=A.filter(function(A){return!A.name.endsWith("/")});return g=g.sort(function(A,M){return new Date(A.lastModified).getTime()-new Date(M.lastModified).getTime()}),M&&(g=g.reverse()),[].concat(I(t),I(g))},M.pathSlice=function(A){A=A.replace(g.minioBrowserPrefix,"");var M="",t="";if(!A)return{bucket:t,prefix:M};var I=A.indexOf("/",1);return I==-1?(t=A.slice(1),{bucket:t,prefix:M}):(t=A.slice(1,I),M=A.slice(I+1),{bucket:t,prefix:M})},M.pathJoin=function(A,M){return M||(M=""),g.minioBrowserPrefix+"/"+A+"/"+M}},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(M,"__esModule",{value:!0});var i=function(){function A(A,M){for(var t=0;t":i.innerHTML="<"+A+">",T[A]=!i.firstChild),T[A]?C[A]:null}var g=t(10),e=t(2),i=g.canUseDOM?document.createElement("div"):null,T={},E=[1,'"],N=[1,"","
    "],o=[3,"","
    "],n=[1,'',""],C={"*":[1,"?
    ","
    "],area:[1,"",""],col:[2,"","
    "],legend:[1,"
    ","
    "],param:[1,"",""],tr:[2,"","
    "],optgroup:E,option:E,caption:N,colgroup:N,tbody:N,tfoot:N,thead:N,td:o,th:o},c=["circle","clipPath","defs","ellipse","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","text","tspan"];c.forEach(function(A){C[A]=n,T[A]=!0}),A.exports=I},function(A,M){"use strict";function t(A,M){if(A===M)return!0;if("object"!=typeof A||null===A||"object"!=typeof M||null===M)return!1;var t=Object.keys(A),g=Object.keys(M);if(t.length!==g.length)return!1;for(var e=I.bind(M),i=0;i-1&&A%1==0&&A1)for(var t=1;tA.clientHeight}Object.defineProperty(M,"__esModule",{value:!0}),M.default=i;var T=t(57),E=I(T),N=t(39),o=I(N);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M,t,I,g){var i=A[M],E="undefined"==typeof i?"undefined":e(i);return T.default.isValidElement(i)?new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of type ReactElement "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected an element type (a string ")+"or a ReactClass)."):"function"!==E&&"string"!==E?new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of value ` + "`" + `"+i+"` + "`" + ` "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected an element type (a string ")+"or a ReactClass)."):null}M.__esModule=!0;var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol?"symbol":typeof A},i=t(1),T=I(i),E=t(182),N=I(E);M.default=(0,N.default)(g)},function(A,M){"use strict";function t(A){function M(M,t,I,g,e,i){var T=g||"<>",E=i||I;if(null==t[I])return M?new Error("Required "+e+" ` + "`" + `"+E+"` + "`" + ` was not specified "+("in ` + "`" + `"+T+"` + "`" + `.")):null;for(var N=arguments.length,o=Array(N>6?N-6:0),n=6;n=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){return 0===A.button}function i(A){return!!(A.metaKey||A.altKey||A.ctrlKey||A.shiftKey)}function T(A){for(var M in A)if(Object.prototype.hasOwnProperty.call(A,M))return!1;return!0}function E(A,M){var t=M.query,I=M.hash,g=M.state;return t||I||g?{pathname:A,query:t,hash:I,state:g}:A}M.__esModule=!0;var N=Object.assign||function(A){for(var M=1;M=0;I--){var g=A[I],e=g.path||"";if(t=e.replace(/\/*$/,"/")+t,0===e.indexOf("/"))break}return"/"+t}},propTypes:{path:C,from:C,to:C.isRequired,query:c,state:c,onEnter:o.falsy,children:o.falsy},render:function(){(0,T.default)(!1)}});M.default=D,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}M.__esModule=!0;var g=t(1),e=I(g),i=t(8),T=I(i),E=t(30),N=t(34),o=e.default.PropTypes,n=o.string,C=o.func,c=e.default.createClass({displayName:"Route",statics:{createRouteFromReactElement:E.createRouteFromReactElement},propTypes:{path:n,component:N.component,components:N.components,getComponent:C,getComponents:C},render:function(){(0,T.default)(!1)}});M.default=c,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){return!A||!A.__v2_compatible__}function i(A){return A&&A.getCurrentLocation}M.__esModule=!0;var T=Object.assign||function(A){for(var M=1;M=0&&0===window.sessionStorage.length)return;throw A}}function i(A){var M=void 0;try{M=window.sessionStorage.getItem(g(A))}catch(A){if(A.name===o)return null}if(M)try{return JSON.parse(M)}catch(A){}return null}M.__esModule=!0,M.saveState=e,M.readState=i;var T=t(23),E=(I(T),"@@History/"),N=["QuotaExceededError","QUOTA_EXCEEDED_ERR"],o="SecurityError"},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A){function M(A){return E.canUseDOM?void 0:T.default(!1),t.listen(A)}var t=n.default(e({getUserConfirmation:N.getUserConfirmation},A,{go:N.go}));return e({},t,{listen:M})}M.__esModule=!0;var e=Object.assign||function(A){for(var M=1;M1?M-1:0),e=1;e=A.childNodes.length?null:A.childNodes.item(t);A.insertBefore(M,I)}var g=t(433),e=t(220),i=t(17),T=t(76),E=t(121),N=t(2),o={dangerouslyReplaceNodeWithMarkup:g.dangerouslyReplaceNodeWithMarkup,updateTextContent:E,processUpdates:function(A,M){for(var t,i=null,o=null,n=0;n-1?void 0:i(!1),!N.plugins[t]){M.extractEvents?void 0:i(!1),N.plugins[t]=M;var I=M.eventTypes;for(var e in I)g(I[e],M,e)?void 0:i(!1)}}}function g(A,M,t){N.eventNameDispatchConfigs.hasOwnProperty(t)?i(!1):void 0,N.eventNameDispatchConfigs[t]=A;var I=A.phasedRegistrationNames;if(I){for(var g in I)if(I.hasOwnProperty(g)){var T=I[g];e(T,M,t)}return!0}return!!A.registrationName&&(e(A.registrationName,M,t),!0)}function e(A,M,t){N.registrationNameModules[A]?i(!1):void 0,N.registrationNameModules[A]=M,N.registrationNameDependencies[A]=M.eventTypes[t].dependencies}var i=t(2),T=null,E={},N={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},injectEventPluginOrder:function(A){T?i(!1):void 0,T=Array.prototype.slice.call(A),I()},injectEventPluginsByName:function(A){var M=!1;for(var t in A)if(A.hasOwnProperty(t)){var g=A[t];E.hasOwnProperty(t)&&E[t]===g||(E[t]?i(!1):void 0,E[t]=g,M=!0)}M&&I()},getPluginModuleForEvent:function(A){var M=A.dispatchConfig;if(M.registrationName)return N.registrationNameModules[M.registrationName]||null;for(var t in M.phasedRegistrationNames)if(M.phasedRegistrationNames.hasOwnProperty(t)){var I=N.registrationNameModules[M.phasedRegistrationNames[t]];if(I)return I}return null},_resetEventPlugins:function(){T=null;for(var A in E)E.hasOwnProperty(A)&&delete E[A];N.plugins.length=0;var M=N.eventNameDispatchConfigs;for(var t in M)M.hasOwnProperty(t)&&delete M[t];var I=N.registrationNameModules;for(var g in I)I.hasOwnProperty(g)&&delete I[g]}};A.exports=N},function(A,M,t){"use strict";function I(A){return(""+A).replace(x,"//")}function g(A,M){this.func=A,this.context=M,this.count=0}function e(A,M,t){var I=A.func,g=A.context;I.call(g,M,A.count++)}function i(A,M,t){if(null==A)return A;var I=g.getPooled(M,t);Q(A,e,I),g.release(I)}function T(A,M,t,I){this.result=A,this.keyPrefix=M,this.func=t,this.context=I,this.count=0}function E(A,M,t){var g=A.result,e=A.keyPrefix,i=A.func,T=A.context,E=i.call(T,M,A.count++);Array.isArray(E)?N(E,g,t,B.thatReturnsArgument):null!=E&&(a.isValidElement(E)&&(E=a.cloneAndReplaceKey(E,e+(E!==M?I(E.key||"")+"/":"")+t)),g.push(E))}function N(A,M,t,g,e){var i="";null!=t&&(i=I(t)+"/");var N=T.getPooled(M,i,g,e);Q(A,E,N),T.release(N)}function o(A,M,t){if(null==A)return A;var I=[];return N(A,I,null,M,t),I}function n(A,M,t){return null}function C(A,M){return Q(A,n,null)}function c(A){var M=[];return N(A,M,null,B.thatReturnsArgument),M}var D=t(31),a=t(13),B=t(20),Q=t(123),r=D.twoArgumentPooler,s=D.fourArgumentPooler,x=/\/(?!\/)/g;g.prototype.destructor=function(){this.func=null,this.context=null,this.count=0},D.addPoolingTo(g,r),T.prototype.destructor=function(){this.result=null,this.keyPrefix=null,this.func=null,this.context=null,this.count=0},D.addPoolingTo(T,s);var j={forEach:i,map:o,mapIntoWithKeyPrefixInternal:N,count:C,toArray:c};A.exports=j},function(A,M,t){"use strict";function I(A,M){var t=y.hasOwnProperty(M)?y[M]:null;w.hasOwnProperty(M)&&(t!==x.OVERRIDE_BASE?B(!1):void 0),A.hasOwnProperty(M)&&(t!==x.DEFINE_MANY&&t!==x.DEFINE_MANY_MERGED?B(!1):void 0)}function g(A,M){if(M){"function"==typeof M?B(!1):void 0,C.isValidElement(M)?B(!1):void 0;var t=A.prototype;M.hasOwnProperty(s)&&u.mixins(A,M.mixins);for(var g in M)if(M.hasOwnProperty(g)&&g!==s){var e=M[g];if(I(t,g),u.hasOwnProperty(g))u[g](A,e);else{var i=y.hasOwnProperty(g),N=t.hasOwnProperty(g),o="function"==typeof e,n=o&&!i&&!N&&M.autobind!==!1;if(n)t.__reactAutoBindMap||(t.__reactAutoBindMap={}),t.__reactAutoBindMap[g]=e,t[g]=e;else if(N){var c=y[g];!i||c!==x.DEFINE_MANY_MERGED&&c!==x.DEFINE_MANY?B(!1):void 0,c===x.DEFINE_MANY_MERGED?t[g]=T(t[g],e):c===x.DEFINE_MANY&&(t[g]=E(t[g],e))}else t[g]=e}}}}function e(A,M){if(M)for(var t in M){var I=M[t];if(M.hasOwnProperty(t)){var g=t in u;g?B(!1):void 0;var e=t in A;e?B(!1):void 0,A[t]=I}}}function i(A,M){A&&M&&"object"==typeof A&&"object"==typeof M?void 0:B(!1);for(var t in M)M.hasOwnProperty(t)&&(void 0!==A[t]?B(!1):void 0,A[t]=M[t]);return A}function T(A,M){return function(){var t=A.apply(this,arguments),I=M.apply(this,arguments);if(null==t)return I;if(null==I)return t;var g={};return i(g,t),i(g,I),g}}function E(A,M){return function(){A.apply(this,arguments),M.apply(this,arguments)}}function N(A,M){var t=M.bind(A);return t}function o(A){for(var M in A.__reactAutoBindMap)if(A.__reactAutoBindMap.hasOwnProperty(M)){var t=A.__reactAutoBindMap[M];A[M]=N(A,t)}}var n=t(207),C=t(13),c=(t(71),t(70),t(222)),D=t(4),a=t(50),B=t(2),Q=t(59),r=t(27),s=(t(3),r({mixins:null})),x=Q({DEFINE_ONCE:null,DEFINE_MANY:null,OVERRIDE_BASE:null,DEFINE_MANY_MERGED:null}),j=[],y={mixins:x.DEFINE_MANY,statics:x.DEFINE_MANY,propTypes:x.DEFINE_MANY,contextTypes:x.DEFINE_MANY,childContextTypes:x.DEFINE_MANY,getDefaultProps:x.DEFINE_MANY_MERGED,getInitialState:x.DEFINE_MANY_MERGED,getChildContext:x.DEFINE_MANY_MERGED,render:x.DEFINE_ONCE,componentWillMount:x.DEFINE_MANY,componentDidMount:x.DEFINE_MANY,componentWillReceiveProps:x.DEFINE_MANY,shouldComponentUpdate:x.DEFINE_ONCE,componentWillUpdate:x.DEFINE_MANY,componentDidUpdate:x.DEFINE_MANY,componentWillUnmount:x.DEFINE_MANY,updateComponent:x.OVERRIDE_BASE},u={displayName:function(A,M){A.displayName=M},mixins:function(A,M){if(M)for(var t=0;t"+T+""},receiveComponent:function(A,M){if(A!==this._currentElement){this._currentElement=A;var t=""+A;if(t!==this._stringText){this._stringText=t;var g=i.getNode(this._rootNodeID);I.updateTextContent(g,t)}}},unmountComponent:function(){e.unmountIDFromEnvironment(this._rootNodeID)}}),A.exports=o},function(A,M,t){"use strict";function I(){this.reinitializeTransaction()}var g=t(18),e=t(73),i=t(4),T=t(20),E={initialize:T,close:function(){C.isBatchingUpdates=!1}},N={initialize:T,close:g.flushBatchedUpdates.bind(g)},o=[N,E];i(I.prototype,e.Mixin,{getTransactionWrappers:function(){return o}});var n=new I,C={isBatchingUpdates:!1,batchedUpdates:function(A,M,t,I,g,e){var i=C.isBatchingUpdates;C.isBatchingUpdates=!0,i?A(M,t,I,g,e):n.perform(A,null,M,t,I,g,e)}};A.exports=C},function(A,M,t){"use strict";function I(){if(!L){L=!0,Q.EventEmitter.injectReactEventListener(B),Q.EventPluginHub.injectEventPluginOrder(T),Q.EventPluginHub.injectInstanceHandle(r),Q.EventPluginHub.injectMount(s),Q.EventPluginHub.injectEventPluginsByName({SimpleEventPlugin:u,EnterLeaveEventPlugin:E,ChangeEventPlugin:e,SelectEventPlugin:j,BeforeInputEventPlugin:g}),Q.NativeComponent.injectGenericComponentClass(D),Q.NativeComponent.injectTextComponentClass(a),Q.Class.injectMixin(n),Q.DOMProperty.injectDOMPropertyConfig(o),Q.DOMProperty.injectDOMPropertyConfig(w),Q.EmptyComponent.injectEmptyComponent("noscript"),Q.Updates.injectReconcileTransaction(x),Q.Updates.injectBatchingStrategy(c),Q.RootIndex.injectCreateReactRootIndex(N.canUseDOM?i.createReactRootIndex:y.createReactRootIndex),Q.Component.injectEnvironment(C)}}var g=t(429),e=t(431),i=t(432),T=t(434),E=t(435),N=t(10),o=t(438),n=t(440),C=t(109),c=t(212),D=t(444),a=t(211),B=t(452),Q=t(453),r=t(48),s=t(12),x=t(457),j=t(463),y=t(464),u=t(465),w=t(462),L=!1;A.exports={inject:I}},function(A,M,t){"use strict";function I(){if(n.current){var A=n.current.getName();if(A)return" Check the render method of ` + "`" + `"+A+"` + "`" + `."}return""}function g(A,M){if(A._store&&!A._store.validated&&null==A.key){A._store.validated=!0;e("uniqueKey",A,M)}}function e(A,M,t){var g=I();if(!g){var e="string"==typeof t?t:t.displayName||t.name;e&&(g=" Check the top-level render call using <"+e+">.")}var i=D[A]||(D[A]={});if(i[g])return null;i[g]=!0;var T={parentOrOwner:g,url:" See https://fb.me/react-warning-keys for more information.",childOwner:null};return M&&M._owner&&M._owner!==n.current&&(T.childOwner=" It was passed a child from "+M._owner.getName()+"."),T}function i(A,M){if("object"==typeof A)if(Array.isArray(A))for(var t=0;t/,e={CHECKSUM_ATTR_NAME:"data-react-checksum",addChecksumToMarkup:function(A){var M=I(A);return A.replace(g," "+e.CHECKSUM_ATTR_NAME+'="'+M+'"$&')},canReuseMarkup:function(A,M){var t=M.getAttribute(e.CHECKSUM_ATTR_NAME);t=t&&parseInt(t,10);var g=I(A);return g===t}};A.exports=e},function(A,M,t){"use strict";var I=t(59),g=I({INSERT_MARKUP:null,MOVE_EXISTING:null,REMOVE_NODE:null,SET_MARKUP:null,TEXT_CONTENT:null});A.exports=g},function(A,M,t){"use strict";function I(A){if("function"==typeof A.type)return A.type;var M=A.type,t=n[M];return null==t&&(n[M]=t=N(M)),t}function g(A){return o?void 0:E(!1),new o(A.type,A.props)}function e(A){return new C(A)}function i(A){return A instanceof C}var T=t(4),E=t(2),N=null,o=null,n={},C=null,c={injectGenericComponentClass:function(A){o=A},injectTextComponentClass:function(A){C=A},injectComponentClasses:function(A){T(n,A)}},D={getComponentClassForElement:I,createInternalComponent:g,createInstanceForText:e,isTextComponent:i,injection:c};A.exports=D},function(A,M,t){"use strict";function I(A,M){}var g=(t(3),{isMounted:function(A){return!1},enqueueCallback:function(A,M){},enqueueForceUpdate:function(A){I(A,"forceUpdate")},enqueueReplaceState:function(A,M){I(A,"replaceState")},enqueueSetState:function(A,M){I(A,"setState")},enqueueSetProps:function(A,M){I(A,"setProps")},enqueueReplaceProps:function(A,M){I(A,"replaceProps")}});A.exports=g},function(A,M,t){"use strict";function I(A){function M(M,t,I,g,e,i){if(g=g||y,i=i||I,null==t[I]){var T=s[e];return M?new Error("Required "+T+" ` + "`" + `"+i+"` + "`" + ` was not specified in "+("` + "`" + `"+g+"` + "`" + `.")):null}return A(t,I,g,e,i)}var t=M.bind(null,!1);return t.isRequired=M.bind(null,!0),t}function g(A){function M(M,t,I,g,e){var i=M[t],T=a(i);if(T!==A){var E=s[g],N=B(i);return new Error("Invalid "+E+" ` + "`" + `"+e+"` + "`" + ` of type "+("` + "`" + `"+N+"` + "`" + ` supplied to ` + "`" + `"+I+"` + "`" + `, expected ")+("` + "`" + `"+A+"` + "`" + `."))}return null}return I(M)}function e(){return I(x.thatReturns(null))}function i(A){function M(M,t,I,g,e){var i=M[t];if(!Array.isArray(i)){var T=s[g],E=a(i);return new Error("Invalid "+T+" ` + "`" + `"+e+"` + "`" + ` of type "+("` + "`" + `"+E+"` + "`" + ` supplied to ` + "`" + `"+I+"` + "`" + `, expected an array."))}for(var N=0;N>"}var r=t(13),s=t(70),x=t(20),j=t(118),y="<>",u={array:g("array"),bool:g("boolean"),func:g("function"),number:g("number"),object:g("object"),string:g("string"),any:e(),arrayOf:i,element:T(),instanceOf:E,node:C(),objectOf:o,oneOf:N,oneOfType:n,shape:c};A.exports=u},function(A,M){"use strict";var t={injectCreateReactRootIndex:function(A){I.createReactRootIndex=A}},I={createReactRootIndex:null,injection:t};A.exports=I},function(A,M){"use strict";var t={currentScrollLeft:0,currentScrollTop:0,refreshScrollValues:function(A){t.currentScrollLeft=A.x,t.currentScrollTop=A.y}};A.exports=t},function(A,M,t){"use strict";function I(A,M){if(null==M?g(!1):void 0,null==A)return M;var t=Array.isArray(A),I=Array.isArray(M);return t&&I?(A.push.apply(A,M),A):t?(A.push(M),A):I?[A].concat(M):[A,M]}var g=t(2);A.exports=I},function(A,M){"use strict";var t=function(A,M,t){Array.isArray(A)?A.forEach(M,t):A&&M.call(t,A)};A.exports=t},function(A,M,t){"use strict";function I(){return!e&&g.canUseDOM&&(e="textContent"in document.documentElement?"textContent":"innerText"),e}var g=t(10),e=null;A.exports=I},function(A,M){"use strict";function t(A){var M=A&&A.nodeName&&A.nodeName.toLowerCase();return M&&("input"===M&&I[A.type]||"textarea"===M)}var I={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};A.exports=t},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(){for(var A=arguments.length,M=Array(A),t=0;t=0&&s.splice(M,1)}function T(A){var M=document.createElement("style");return M.type="text/css",e(A,M),M}function E(A){var M=document.createElement("link");return M.rel="stylesheet",e(A,M),M}function N(A,M){var t,I,g;if(M.singleton){var e=r++;t=Q||(Q=T(M)),I=o.bind(null,t,e,!1),g=o.bind(null,t,e,!0)}else A.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(t=E(M),I=C.bind(null,t),g=function(){i(t),t.href&&URL.revokeObjectURL(t.href)}):(t=T(M),I=n.bind(null,t),g=function(){i(t)});return I(A),function(M){if(M){if(M.css===A.css&&M.media===A.media&&M.sourceMap===A.sourceMap)return;I(A=M)}else g()}}function o(A,M,t,I){var g=t?"":I.css;if(A.styleSheet)A.styleSheet.cssText=x(M,g);else{var e=document.createTextNode(g),i=A.childNodes;i[M]&&A.removeChild(i[M]),i.length?A.insertBefore(e,i[M]):A.appendChild(e)}}function n(A,M){var t=M.css,I=M.media;if(I&&A.setAttribute("media",I),A.styleSheet)A.styleSheet.cssText=t;else{for(;A.firstChild;)A.removeChild(A.firstChild);A.appendChild(document.createTextNode(t))}}function C(A,M){var t=M.css,I=M.sourceMap;I&&(t+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(I))))+" */");var g=new Blob([t],{type:"text/css"}),e=A.href;A.href=URL.createObjectURL(g),e&&URL.revokeObjectURL(e)}var c={},D=function(A){var M;return function(){return"undefined"==typeof M&&(M=A.apply(this,arguments)),M}},a=D(function(){return/msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase())}),B=D(function(){return document.head||document.getElementsByTagName("head")[0]}),Q=null,r=0,s=[];A.exports=function(A,M){M=M||{},"undefined"==typeof M.singleton&&(M.singleton=a()),"undefined"==typeof M.insertAt&&(M.insertAt="bottom");var t=g(A);return I(t,M),function(A){for(var e=[],i=0;i",'"',"` + "`" + `"," ","\r","\n","\t"],D=["{","}","|","\\","^","` + "`" + `"].concat(c),a=["'"].concat(D),B=["%","/","?",";","#"].concat(a),Q=["/","?","#"],r=255,s=/^[+a-z0-9A-Z_-]{0,63}$/,x=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,j={javascript:!0,"javascript:":!0},y={javascript:!0,"javascript:":!0},u={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},w=t(360);I.prototype.parse=function(A,M,t){if(!N.isString(A))throw new TypeError("Parameter 'url' must be a string, not "+typeof A);var I=A.indexOf("?"),g=I!==-1&&I127?"x":O[F];if(!m.match(s)){var k=U.slice(0,Y),R=U.slice(Y+1),J=O.match(x);J&&(k.push(J[1]),R.unshift(J[2])),R.length&&(T="/"+R.join(".")+T),this.hostname=k.join(".");break}}}this.hostname.length>r?this.hostname="":this.hostname=this.hostname.toLowerCase(),z||(this.hostname=E.toASCII(this.hostname));var G=this.port?":"+this.port:"",H=this.hostname||"";this.host=H+G,this.href+=this.host,z&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==T[0]&&(T="/"+T))}if(!j[D])for(var Y=0,p=a.length;Y0)&&t.host.split("@");L&&(t.auth=L.shift(),t.host=t.hostname=L.shift())}return t.search=A.search,t.query=A.query,N.isNull(t.pathname)&&N.isNull(t.search)||(t.path=(t.pathname?t.pathname:"")+(t.search?t.search:"")),t.href=t.format(),t}if(!j.length)return t.pathname=null,t.search?t.path="/"+t.search:t.path=null,t.href=t.format(),t;for(var l=j.slice(-1)[0],Y=(t.host||A.host||j.length>1)&&("."===l||".."===l)||""===l,d=0,h=j.length;h>=0;h--)l=j[h],"."===l?j.splice(h,1):".."===l?(j.splice(h,1),d++):d&&(j.splice(h,1),d--);if(!s&&!x)for(;d--;d)j.unshift("..");!s||""===j[0]||j[0]&&"/"===j[0].charAt(0)||j.unshift(""),Y&&"/"!==j.join("/").substr(-1)&&j.push("");var S=""===j[0]||j[0]&&"/"===j[0].charAt(0);if(w){t.hostname=t.host=S?"":j.length?j.shift():"";var L=!!(t.host&&t.host.indexOf("@")>0)&&t.host.split("@");L&&(t.auth=L.shift(),t.host=t.hostname=L.shift())}return s=s||t.host&&j.length,s&&!S&&j.unshift(""),j.length?t.pathname=j.join("/"):(t.pathname=null,t.path=null),N.isNull(t.pathname)&&N.isNull(t.search)||(t.path=(t.pathname?t.pathname:"")+(t.search?t.search:"")),t.auth=A.auth||t.auth,t.slashes=t.slashes||A.slashes,t.href=t.format(),t},I.prototype.parseHost=function(){var A=this.host,M=n.exec(A);M&&(M=M[0],":"!==M&&(this.port=M.substr(1)),A=A.substr(0,A.length-M.length)),A&&(this.hostname=A)}},function(A,M){var t={animationIterationCount:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridColumn:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,stopOpacity:!0,strokeDashoffset:!0,strokeOpacity:!0,strokeWidth:!0};A.exports=function(A,M){return"number"!=typeof M||t[A]?M:M+"px"}},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M,t){return P.LoggedIn()?t():(location.pathname!==z.minioBrowserPrefix&&location.pathname!==z.minioBrowserPrefix+"/"||M(z.minioBrowserPrefix+"/login"),t())}function i(A,M){P.LoggedIn()&&M(""+z.minioBrowserPrefix)}function T(){q<2&&setTimeout(function(){document.querySelector(".page-load").classList.add("pl-"+q),q++,T()},K[q])}t(498);var E=t(1),N=g(E),o=t(16),n=g(o),C=t(484),c=g(C),D=t(125),a=g(D),B=t(230),Q=g(B),r=t(190),s=g(r),x=t(191),j=g(x),y=t(65),u=g(y),w=t(187),L=g(w),l=t(393),Y=g(l),d=t(22),h=g(d),S=t(42),z=(g(S),t(26)),U=t(19),p=I(U),O=t(255),m=g(O),F=t(245),f=g(F),k=t(241),R=g(k),J=t(497),G=(g(J),t(131)),H=g(G),b=t(60),X=g(b);window.Web=H.default;var v=(0,Q.default)(c.default)(a.default)(m.default),W=(0,h.default)(function(A){return A})(R.default),V=(0,h.default)(function(A){return A})(f.default),P=new H.default(window.location.protocol+"//"+window.location.host+z.minioBrowserPrefix+"/webrpc",v.dispatch);window.web=P,v.dispatch(p.setWeb(P));var Z=function(A){return N.default.createElement("div",null,A.children)};n.default.render(N.default.createElement(Y.default,{store:v,web:P},N.default.createElement(j.default,{history:u.default},N.default.createElement(s.default,{path:"/",component:Z},N.default.createElement(s.default,{path:"minio",component:Z},N.default.createElement(L.default,{component:W,onEnter:e}),N.default.createElement(s.default,{path:"login",component:V,onEnter:i}),N.default.createElement(s.default,{path:":bucket",component:W,onEnter:e}),N.default.createElement(s.default,{path:":bucket/*",component:W,onEnter:e}))))),document.getElementById("root"));var K=[0,400],q=0;T(),X.default.getItem("newlyUpdated")&&(v.dispatch(p.showAlert({type:"success",message:"Updated to the latest UI Version."})),X.default.removeItem("newlyUpdated"))},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=function(){function A(A,M){for(var t=0;t-1})))}},{key:"selectPrefix",value:function(A,M){A.preventDefault();var t=this.props,I=(t.dispatch,t.currentPath),g=(t.web,t.currentBucket),e=encodeURI(M);if(M.endsWith("/")||""===M){if(M===I)return;D.default.push(TA.pathJoin(g,e))}else window.location=window.location.origin+"/minio/download/"+g+"/"+e+"?token="+DA.default.getItem("token")}},{key:"makeBucket",value:function(A){A.preventDefault();var M=this.refs.makeBucketRef.value;this.refs.makeBucketRef.value="";var t=this.props,I=t.web,g=t.dispatch;this.hideMakeBucketModal(),I.MakeBucket({bucketName:M}).then(function(){g(eA.addBucket(M)),g(eA.selectBucket(M))}).catch(function(A){return g(eA.showAlert({type:"danger",message:A.message}))})}},{key:"hideMakeBucketModal",value:function(){var A=this.props.dispatch;A(eA.hideMakeBucketModal())}},{key:"showMakeBucketModal",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showMakeBucketModal())}},{key:"showAbout",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showAbout())}},{key:"hideAbout",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.hideAbout())}},{key:"showBucketPolicy",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showBucketPolicy())}},{key:"hideBucketPolicy",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.hideBucketPolicy())}},{key:"uploadFile",value:function(A){A.preventDefault();var M=this.props,t=M.dispatch,I=M.buckets;if(0===I.length)return void t(eA.showAlert({type:"danger",message:"Bucket needs to be created before trying to upload files."}));var g=A.target.files[0];A.target.value=null,this.xhr=new XMLHttpRequest,t(eA.uploadFile(g,this.xhr))}},{key:"removeObject",value:function(){var A=this,M=this.props,t=M.web,I=M.dispatch,g=M.currentPath,e=M.currentBucket,i=M.deleteConfirmation;t.RemoveObject({bucketName:e,objectName:i.object}).then(function(){A.hideDeleteConfirmation(),I(eA.selectPrefix(g))}).catch(function(A){return I(eA.showAlert({type:"danger",message:A.message}))})}},{key:"hideAlert",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.hideAlert())}},{key:"showDeleteConfirmation",value:function(A,M){A.preventDefault();var t=this.props.dispatch;t(eA.showDeleteConfirmation(M))}},{key:"hideDeleteConfirmation",value:function(){var A=this.props.dispatch;A(eA.hideDeleteConfirmation())}},{key:"shareObject",value:function(A,M){A.preventDefault();var t=this.props.dispatch;t(eA.shareObject(M))}},{key:"hideShareObjectModal",value:function(){var A=this.props.dispatch;A(eA.hideShareObject())}},{key:"dataType",value:function(A,M){return NA.getDataType(A,M)}},{key:"sortObjectsByName",value:function(A){var M=this.props,t=M.dispatch,I=M.objects,g=M.sortNameOrder;t(eA.setObjects(TA.sortObjectsByName(I,!g))),t(eA.setSortNameOrder(!g))}},{key:"sortObjectsBySize",value:function(){var A=this.props,M=A.dispatch,t=A.objects,I=A.sortSizeOrder;M(eA.setObjects(TA.sortObjectsBySize(t,!I))),M(eA.setSortSizeOrder(!I))}},{key:"sortObjectsByDate",value:function(){var A=this.props,M=A.dispatch,t=A.objects,I=A.sortDateOrder;M(eA.setObjects(TA.sortObjectsByDate(t,!I))),M(eA.setSortDateOrder(!I))}},{key:"logout",value:function(A){var M=this.props.web;A.preventDefault(),M.Logout(),D.default.push(oA.minioBrowserPrefix+"/login")}},{key:"landingPage",value:function(A){A.preventDefault(),this.props.dispatch(eA.selectBucket(this.props.buckets[0]))}},{key:"fullScreen",value:function(A){A.preventDefault();var M=document.documentElement;M.requestFullscreen&&M.requestFullscreen(),M.mozRequestFullScreen&&M.mozRequestFullScreen(),M.webkitRequestFullscreen&&M.webkitRequestFullscreen(),M.msRequestFullscreen&&M.msRequestFullscreen()}},{key:"toggleSidebar",value:function(A){this.props.dispatch(eA.setSidebarStatus(A))}},{key:"hideSidebar",value:function(A){var M=A||window.event,t=M.srcElement||M.target;3===t.nodeType&&(t=t.parentNode);var I=t.id;"feh-trigger"!==I&&this.props.dispatch(eA.setSidebarStatus(!1))}},{key:"showSettings",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showSettings())}},{key:"showMessage",value:function(){var A=this.props.dispatch;A(eA.showAlert({type:"success",message:"Link copied to clipboard!"})),this.hideShareObjectModal()}},{key:"selectTexts",value:function(){this.refs.copyTextInput.select()}},{key:"handleExpireValue",value:function(A,M){M===-1?this.refs[A].stepDown(1):this.refs[A].stepUp(1),7==this.refs.expireDays.value&&(this.refs.expireHours.value=0,this.refs.expireMins.value=0)}},{key:"render",value:function(){var A=this.props.storageInfo,M=A.total,t=A.free,I=this.props,g=I.showMakeBucketModal,e=I.alert,i=I.sortNameOrder,T=I.sortSizeOrder,E=I.sortDateOrder,N=I.showAbout,n=I.showBucketPolicy,c=this.props.serverInfo,D=c.version,a=c.memory,Q=c.platform,r=c.runtime,x=this.props.sidebarStatus,y=this.props.showSettings,w=this.props,l=w.policies,d=w.currentBucket,S=(w.currentPath,this.props.deleteConfirmation),U=this.props.shareObject,p=this.props,O=p.web,F=p.prefixWritable,k=y?o.default.createElement(V.default,null):o.default.createElement("noscript",null),J=o.default.createElement(L.default,{className:(0,C.default)({alert:!0,animated:!0,fadeInDown:e.show,fadeOutUp:!e.show}),bsStyle:e.type,onDismiss:this.hideAlert.bind(this)},o.default.createElement("div",{className:"text-center"},e.message));e.message||(J="");var H=(o.default.createElement(h.default,{id:"tt-sign-out"},"Sign out"),o.default.createElement(h.default,{id:"tt-upload-file"},"Upload file")),X=o.default.createElement(h.default,{id:"tt-create-bucket"},"Create bucket"),W="",P="",K="",_=M-t,AA=_/M*100+"%";O.LoggedIn()?P=o.default.createElement($.default,{fullScreen:this.fullScreen.bind(this),showAbout:this.showAbout.bind(this),showSettings:this.showSettings.bind(this),logout:this.logout.bind(this)}):W=o.default.createElement("a",{className:"btn btn-danger",href:"/minio/login"},"Login"),O.LoggedIn()&&(K=o.default.createElement("div",{className:"feh-usage"},o.default.createElement("div",{className:"fehu-chart"},o.default.createElement("div",{style:{width:AA}})),o.default.createElement("ul",null,o.default.createElement("li",null,"Used:",B.default.filesize(M-t)),o.default.createElement("li",{className:"pull-right"},"Free:",B.default.filesize(M-_)))));var tA="";return O.LoggedIn()?tA=o.default.createElement(z.default,{dropup:!0,className:"feb-actions",id:"fe-action-toggle"},o.default.createElement(z.default.Toggle,{noCaret:!0,className:"feba-toggle"},o.default.createElement("span",null,o.default.createElement("i",{className:"fa fa-plus"}))),o.default.createElement(z.default.Menu,null,o.default.createElement(Y.default,{placement:"left",overlay:H},o.default.createElement("a",{href:"#",className:"feba-btn feba-upload"},o.default.createElement("input",{type:"file",onChange:this.uploadFile.bind(this),style:{display:"none"},id:"file-input"}),o.default.createElement("label",{htmlFor:"file-input"}," ",o.default.createElement("i",{className:"fa fa-cloud-upload"})," "))),o.default.createElement(Y.default,{placement:"left",overlay:X},o.default.createElement("a",{href:"#",className:"feba-btn feba-bucket",onClick:this.showMakeBucketModal.bind(this)},o.default.createElement("i",{className:"fa fa-hdd-o"}))))):F&&(tA=o.default.createElement(z.default,{dropup:!0,className:"feb-actions",id:"fe-action-toggle"},o.default.createElement(z.default.Toggle,{noCaret:!0,className:"feba-toggle"},o.default.createElement("span",null,o.default.createElement("i",{className:"fa fa-plus"}))),o.default.createElement(z.default.Menu,null,o.default.createElement(Y.default,{placement:"left",overlay:H},o.default.createElement("a",{href:"#",className:"feba-btn feba-upload"},o.default.createElement("input",{type:"file",onChange:this.uploadFile.bind(this),style:{display:"none"},id:"file-input"}),o.default.createElement("label",{htmlFor:"file-input"}," ",o.default.createElement("i",{className:"fa fa-cloud-upload"})," ")))))),o.default.createElement("div",{className:(0,C.default)({"file-explorer":!0,toggled:x})},o.default.createElement(R.default,{landingPage:this.landingPage.bind(this),searchBuckets:this.searchBuckets.bind(this),selectBucket:this.selectBucket.bind(this),clickOutside:this.hideSidebar.bind(this),showPolicy:this.showBucketPolicy.bind(this)}),o.default.createElement("div",{className:"fe-body"},o.default.createElement(m.default,null,J,o.default.createElement("header",{className:"fe-header-mobile hidden-lg hidden-md"},o.default.createElement("div",{id:"feh-trigger",className:"feh-trigger "+(0,C.default)({"feht-toggled":x}),onClick:this.toggleSidebar.bind(this,!x)},o.default.createElement("div",{className:"feht-lines"},o.default.createElement("div",{className:"top"}),o.default.createElement("div",{className:"center"}),o.default.createElement("div",{className:"bottom"}))),o.default.createElement("img",{className:"mh-logo",src:IA.default,alt:""})),o.default.createElement("header",{className:"fe-header"},o.default.createElement(G.default,{selectPrefix:this.selectPrefix.bind(this)}),K,o.default.createElement("ul",{className:"feh-actions"},o.default.createElement(b.default,null),W,P)),o.default.createElement("div",{className:"feb-container"},o.default.createElement("header",{className:"fesl-row","data-type":"folder"},o.default.createElement("div",{className:"fesl-item fi-name",onClick:this.sortObjectsByName.bind(this),"data-sort":"name"},"Name",o.default.createElement("i",{className:(0,C.default)({"fesli-sort":!0,fa:!0,"fa-sort-alpha-desc":i,"fa-sort-alpha-asc":!i})})),o.default.createElement("div",{className:"fesl-item fi-size",onClick:this.sortObjectsBySize.bind(this),"data-sort":"size"},"Size",o.default.createElement("i",{className:(0,C.default)({"fesli-sort":!0,fa:!0,"fa-sort-amount-desc":T,"fa-sort-amount-asc":!T})})),o.default.createElement("div",{className:"fesl-item fi-modified",onClick:this.sortObjectsByDate.bind(this),"data-sort":"last-modified"},"Last Modified",o.default.createElement("i",{className:(0,C.default)({"fesli-sort":!0,fa:!0,"fa-sort-numeric-desc":E,"fa-sort-numeric-asc":!E})})),o.default.createElement("div",{className:"fesl-item fi-actions"}))),o.default.createElement("div",{className:"feb-container"},o.default.createElement(f.default,{dataType:this.dataType.bind(this),selectPrefix:this.selectPrefix.bind(this),showDeleteConfirmation:this.showDeleteConfirmation.bind(this),shareObject:this.shareObject.bind(this)})),o.default.createElement(v.default,null),tA,o.default.createElement(s.default,{className:"modal-create-bucket",bsSize:"small",animation:!1,show:g,onHide:this.hideMakeBucketModal.bind(this)},o.default.createElement("button",{className:"close close-alt",onClick:this.hideMakeBucketModal.bind(this)},o.default.createElement("span",null,"×")),o.default.createElement(j.default,null,o.default.createElement("form",{onSubmit:this.makeBucket.bind(this)},o.default.createElement("div",{className:"input-group"},o.default.createElement("input",{className:"ig-text",type:"text",ref:"makeBucketRef",placeholder:"Bucket Name",autoFocus:!0}),o.default.createElement("i",{className:"ig-helpers"}))))),o.default.createElement(s.default,{className:"modal-about modal-dark",animation:!1,show:N,onHide:this.hideAbout.bind(this)},o.default.createElement("button",{className:"close",onClick:this.hideAbout.bind(this)},o.default.createElement("span",null,"×")),o.default.createElement("div",{className:"ma-inner"},o.default.createElement("div",{className:"mai-item hidden-xs"},o.default.createElement("a",{href:"https://minio.io",target:"_blank"},o.default.createElement("img",{className:"maii-logo",src:IA.default,alt:""}))),o.default.createElement("div",{className:"mai-item"},o.default.createElement("ul",{className:"maii-list"},o.default.createElement("li",null,o.default.createElement("div",null,"Version"),o.default.createElement("small",null,D)),o.default.createElement("li",null,o.default.createElement("div",null,"Memory"),o.default.createElement("small",null,a)),o.default.createElement("li",null,o.default.createElement("div",null,"Platform"),o.default.createElement("small",null,Q)),o.default.createElement("li",null,o.default.createElement("div",null,"Runtime"),o.default.createElement("small",null,r)))))),o.default.createElement(s.default,{className:"modal-policy",animation:!1,show:n,onHide:this.hideBucketPolicy.bind(this)},o.default.createElement(u.default,null,"Bucket Policy (",d,")",o.default.createElement("button",{className:"close close-alt",onClick:this.hideBucketPolicy.bind(this)},o.default.createElement("span",null,"×"))),o.default.createElement("div",{className:"pm-body"},o.default.createElement(Z.default,{bucket:d}),l.map(function(A,M){return o.default.createElement(q.default,{key:M,prefix:A.prefix,policy:A.policy})}))),o.default.createElement(MA.default,{show:S.show,icon:"fa fa-exclamation-triangle mci-red",text:"Are you sure you want to delete?",sub:"This cannot be undone!",okText:"Delete",cancelText:"Cancel",okHandler:this.removeObject.bind(this),cancelHandler:this.hideDeleteConfirmation.bind(this)}),o.default.createElement(s.default,{show:U.show,animation:!1,onHide:this.hideShareObjectModal.bind(this),bsSize:"small"},o.default.createElement(u.default,null,"Share Object"),o.default.createElement(j.default,null,o.default.createElement("div",{className:"input-group copy-text"},o.default.createElement("label",null,"Shareable Link"),o.default.createElement("input",{type:"text",ref:"copyTextInput",readOnly:"readOnly",value:window.location.protocol+"//"+U.url,onClick:this.selectTexts.bind(this)})),o.default.createElement("div",{className:"input-group",style:{display:O.LoggedIn()?"block":"none"}},o.default.createElement("label",null,"Expires in"),o.default.createElement("div",{className:"set-expire"},o.default.createElement("div",{className:"set-expire-item"},o.default.createElement("i",{className:"set-expire-increase",onClick:this.handleExpireValue.bind(this,"expireDays",1)}),o.default.createElement("div",{className:"set-expire-title"},"Days"),o.default.createElement("div",{className:"set-expire-value"},o.default.createElement("input",{ref:"expireDays",type:"number",min:0,max:7,defaultValue:0})),o.default.createElement("i",{className:"set-expire-decrease",onClick:this.handleExpireValue.bind(this,"expireDays",-1)})),o.default.createElement("div",{className:"set-expire-item"},o.default.createElement("i",{className:"set-expire-increase",onClick:this.handleExpireValue.bind(this,"expireHours",1)}),o.default.createElement("div",{className:"set-expire-title"},"Hours"),o.default.createElement("div",{className:"set-expire-value"},o.default.createElement("input",{ref:"expireHours",type:"number",min:0,max:24,defaultValue:0})),o.default.createElement("i",{className:"set-expire-decrease",onClick:this.handleExpireValue.bind(this,"expireHours",-1)})),o.default.createElement("div",{className:"set-expire-item"},o.default.createElement("i",{className:"set-expire-increase",onClick:this.handleExpireValue.bind(this,"expireMins",1)}),o.default.createElement("div",{className:"set-expire-title"},"Minutes"),o.default.createElement("div",{className:"set-expire-value"},o.default.createElement("input",{ref:"expireMins",type:"number",min:1,max:60,defaultValue:45})),o.default.createElement("i",{className:"set-expire-decrease",onClick:this.handleExpireValue.bind(this,"expireMins",-1)}))))),o.default.createElement("div",{className:"modal-footer"},o.default.createElement(CA.default,{text:U.url,onCopy:this.showMessage.bind(this)},o.default.createElement("button",{className:"btn btn-success"},"Copy Link")),o.default.createElement("button",{className:"btn btn-link",onClick:this.hideShareObjectModal.bind(this)},"Cancel"))),k)))}}]),M}(o.default.Component);M.default=aA},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var g=t(1),e=I(g),i=t(22),T=I(i),E=t(91),N=I(E),o=function(A){var M=A.fullScreen,t=A.showAbout,I=A.showSettings,g=A.logout;return e.default.createElement("li",null,e.default.createElement(N.default,{pullRight:!0,id:"top-right-menu"},e.default.createElement(N.default.Toggle,{noCaret:!0},e.default.createElement("i",{className:"fa fa-reorder"})),e.default.createElement(N.default.Menu,{className:"dropdown-menu-right"},e.default.createElement("li",null,e.default.createElement("a",{target:"_blank",href:"https://github.com/minio/miniobrowser"},"Github ",e.default.createElement("i",{className:"fa fa-github"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:M},"Fullscreen ",e.default.createElement("i",{className:"fa fa-expand"}))),e.default.createElement("li",null,e.default.createElement("a",{target:"_blank",href:"https://docs.minio.io/"},"Documentation ",e.default.createElement("i",{className:"fa fa-book"}))),e.default.createElement("li",null,e.default.createElement("a",{target:"_blank",href:"https://slack.minio.io"},"Ask for help ",e.default.createElement("i",{className:"fa fa-question-circle"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:t},"About ",e.default.createElement("i",{className:"fa fa-info-circle"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:I},"Settings ",e.default.createElement("i",{className:"fa fa-cog"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:g},"Sign Out ",e.default.createElement("i",{className:"fa fa-sign-out"}))))))};M.default=(0,T.default)(function(A){return A})(o)},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var g=t(1),e=I(g),i=t(22),T=I(i),E=t(95),N=I(E),o=t(94),n=I(o),C=function(A){var M=A.latestUiVersion;return M===currentUiVersion?e.default.createElement("noscript",null):e.default.createElement("li",{className:"hidden-xs hidden-sm"},e.default.createElement("a",{href:""},e.default.createElement(n.default,{placement:"left",overlay:e.default.createElement(N.default,{id:"tt-version-update"},"New update available. Click to refresh.")}," ",e.default.createElement("i",{className:"fa fa-refresh"})," ")))};M.default=(0,T.default)(function(A){return{latestUiVersion:A.latestUiVersion}})(C)},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){ -if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=function(){function A(A,M){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{buckets:[],visibleBuckets:[],objects:[],storageInfo:{},serverInfo:{},currentBucket:"",currentPath:"",showMakeBucketModal:!1,uploads:{},alert:{show:!1,type:"danger",message:""},loginError:!1,sortNameOrder:!1,sortSizeOrder:!1,sortDateOrder:!1,latestUiVersion:currentUiVersion,sideBarActive:!1,loginRedirectPath:E.minioBrowserPrefix,settings:{accessKey:"",secretKey:"",secretKeyVisible:!1},showSettings:!1,policies:[],deleteConfirmation:{object:"",show:!1},shareObject:{show:!1,url:"",expiry:604800},prefixWritable:!1},M=arguments[1],t=Object.assign({},A);switch(M.type){case T.SET_WEB:t.web=M.web;break;case T.SET_BUCKETS:t.buckets=M.buckets;break;case T.ADD_BUCKET:t.buckets=[M.bucket].concat(e(t.buckets)),t.visibleBuckets=[M.bucket].concat(e(t.visibleBuckets));break;case T.SET_VISIBLE_BUCKETS:t.visibleBuckets=M.visibleBuckets;break;case T.SET_CURRENT_BUCKET:t.currentBucket=M.currentBucket;break;case T.SET_OBJECTS:t.objects=M.objects;break;case T.SET_CURRENT_PATH:t.currentPath=M.currentPath;break;case T.SET_STORAGE_INFO:t.storageInfo=M.storageInfo;break;case T.SET_SERVER_INFO:t.serverInfo=M.serverInfo;break;case T.SHOW_MAKEBUCKET_MODAL:t.showMakeBucketModal=M.showMakeBucketModal;break;case T.UPLOAD_PROGRESS:t.uploads=Object.assign({},t.uploads),t.uploads[M.slug].loaded=M.loaded;break;case T.ADD_UPLOAD:t.uploads=Object.assign({},t.uploads,g({},M.slug,{loaded:0,size:M.size,xhr:M.xhr,name:M.name}));break;case T.STOP_UPLOAD:t.uploads=Object.assign({},t.uploads),delete t.uploads[M.slug];break;case T.SET_ALERT:t.alert.alertTimeout&&clearTimeout(t.alert.alertTimeout),M.alert.show?t.alert=M.alert:t.alert=Object.assign({},t.alert,{show:!1});break;case T.SET_LOGIN_ERROR:t.loginError=!0;break;case T.SET_SHOW_ABORT_MODAL:t.showAbortModal=M.showAbortModal;break;case T.SHOW_ABOUT:t.showAbout=M.showAbout;break;case T.SET_SORT_NAME_ORDER:t.sortNameOrder=M.sortNameOrder;break;case T.SET_SORT_SIZE_ORDER:t.sortSizeOrder=M.sortSizeOrder;break;case T.SET_SORT_DATE_ORDER:t.sortDateOrder=M.sortDateOrder;break;case T.SET_LATEST_UI_VERSION:t.latestUiVersion=M.latestUiVersion;break;case T.SET_SIDEBAR_STATUS:t.sidebarStatus=M.sidebarStatus;break;case T.SET_LOGIN_REDIRECT_PATH:t.loginRedirectPath=M.path;case T.SET_LOAD_BUCKET:t.loadBucket=M.loadBucket;break;case T.SET_LOAD_PATH:t.loadPath=M.loadPath;break;case T.SHOW_SETTINGS:t.showSettings=M.showSettings;break;case T.SET_SETTINGS:t.settings=Object.assign({},t.settings,M.settings);break;case T.SHOW_BUCKET_POLICY:t.showBucketPolicy=M.showBucketPolicy;break;case T.SET_POLICIES:t.policies=M.policies;break;case T.DELETE_CONFIRMATION:t.deleteConfirmation=Object.assign({},M.payload);break;case T.SET_SHARE_OBJECT:t.shareObject=Object.assign({},M.shareObject);break;case T.SET_PREFIX_WRITABLE:t.prefixWritable=M.prefixWritable}return t}},function(A,M,t){A.exports={default:t(260),__esModule:!0}},function(A,M,t){t(270),A.exports=t(49).Object.assign},function(A,M,t){var I=t(80);A.exports=function(A,M){return I.create(A,M)}},function(A,M,t){t(271),A.exports=t(49).Object.keys},function(A,M,t){t(272),A.exports=t(49).Object.setPrototypeOf},function(A,M){A.exports=function(A){if("function"!=typeof A)throw TypeError(A+" is not a function!");return A}},function(A,M,t){var I=t(136);A.exports=function(A){if(!I(A))throw TypeError(A+" is not an object!");return A}},function(A,M){var t={}.toString;A.exports=function(A){return t.call(A).slice(8,-1)}},function(A,M){A.exports=function(A){if(void 0==A)throw TypeError("Can't call method on "+A);return A}},function(A,M){var t=A.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=t)},function(A,M,t){var I=t(263);A.exports=Object("z").propertyIsEnumerable(0)?Object:function(A){return"String"==I(A)?A.split(""):Object(A)}},function(A,M,t){var I=t(80),g=t(137),e=t(266);A.exports=t(135)(function(){var A=Object.assign,M={},t={},I=Symbol(),g="abcdefghijklmnopqrst";return M[I]=7,g.split("").forEach(function(A){t[A]=A}),7!=A({},M)[I]||Object.keys(A({},t)).join("")!=g})?function(A,M){for(var t=g(A),i=arguments,T=i.length,E=1,N=I.getKeys,o=I.getSymbols,n=I.isEnum;T>E;)for(var C,c=e(i[E++]),D=o?N(c).concat(o(c)):N(c),a=D.length,B=0;a>B;)n.call(c,C=D[B++])&&(t[C]=c[C]);return t}:Object.assign},function(A,M,t){var I=t(79),g=t(49),e=t(135);A.exports=function(A,M){var t=(g.Object||{})[A]||Object[A],i={};i[A]=M(t),I(I.S+I.F*e(function(){t(1)}),"Object",i)}},function(A,M,t){var I=t(80).getDesc,g=t(136),e=t(262),i=function(A,M){if(e(A),!g(M)&&null!==M)throw TypeError(M+": can't set as prototype!")};A.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(A,M,g){try{g=t(134)(Function.call,I(Object.prototype,"__proto__").set,2),g(A,[]),M=!(A instanceof Array)}catch(A){M=!0}return function(A,t){return i(A,t),M?A.__proto__=t:g(A,t),A}}({},!1):void 0),check:i}},function(A,M,t){var I=t(79);I(I.S+I.F,"Object",{assign:t(267)})},function(A,M,t){var I=t(137);t(268)("keys",function(A){return function(M){return A(I(M))}})},function(A,M,t){var I=t(79);I(I.S,"Object",{setPrototypeOf:t(269).set})},function(A,M,t){function I(A){if(A)return g(A)}function g(A){ -for(var M in I.prototype)A[M]=I.prototype[M];return A}A.exports=I,I.prototype.on=I.prototype.addEventListener=function(A,M){return this._callbacks=this._callbacks||{},(this._callbacks["$"+A]=this._callbacks["$"+A]||[]).push(M),this},I.prototype.once=function(A,M){function t(){this.off(A,t),M.apply(this,arguments)}return t.fn=M,this.on(A,t),this},I.prototype.off=I.prototype.removeListener=I.prototype.removeAllListeners=I.prototype.removeEventListener=function(A,M){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var t=this._callbacks["$"+A];if(!t)return this;if(1==arguments.length)return delete this._callbacks["$"+A],this;for(var I,g=0;g-1&&A%1==0&&A1)for(var t=1;tA.clientHeight}Object.defineProperty(M,"__esModule",{value:!0}),M.default=i;var T=t(57),E=I(T),N=t(39),o=I(N);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M,t,I,g){var i=A[M],E="undefined"==typeof i?"undefined":e(i);return T.default.isValidElement(i)?new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of type ReactElement "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected an element type (a string ")+"or a ReactClass)."):"function"!==E&&"string"!==E?new Error("Invalid "+I+" ` + "`" + `"+g+"` + "`" + ` of value ` + "`" + `"+i+"` + "`" + ` "+("supplied to ` + "`" + `"+t+"` + "`" + `, expected an element type (a string ")+"or a ReactClass)."):null}M.__esModule=!0;var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol?"symbol":typeof A},i=t(1),T=I(i),E=t(182),N=I(E);M.default=(0,N.default)(g)},function(A,M){"use strict";function t(A){function M(M,t,I,g,e,i){var T=g||"<>",E=i||I;if(null==t[I])return M?new Error("Required "+e+" ` + "`" + `"+E+"` + "`" + ` was not specified "+("in ` + "`" + `"+T+"` + "`" + `.")):null;for(var N=arguments.length,o=Array(N>6?N-6:0),n=6;n=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){return 0===A.button}function i(A){return!!(A.metaKey||A.altKey||A.ctrlKey||A.shiftKey)}function T(A){for(var M in A)if(Object.prototype.hasOwnProperty.call(A,M))return!1;return!0}function E(A,M){var t=M.query,I=M.hash,g=M.state;return t||I||g?{pathname:A,query:t,hash:I,state:g}:A}M.__esModule=!0;var N=Object.assign||function(A){for(var M=1;M=0;I--){var g=A[I],e=g.path||"";if(t=e.replace(/\/*$/,"/")+t,0===e.indexOf("/"))break}return"/"+t}},propTypes:{path:C,from:C,to:C.isRequired,query:c,state:c,onEnter:o.falsy,children:o.falsy},render:function(){(0,T.default)(!1)}});M.default=D,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}M.__esModule=!0;var g=t(1),e=I(g),i=t(8),T=I(i),E=t(30),N=t(34),o=e.default.PropTypes,n=o.string,C=o.func,c=e.default.createClass({displayName:"Route",statics:{createRouteFromReactElement:E.createRouteFromReactElement},propTypes:{path:n,component:N.component,components:N.components,getComponent:C,getComponents:C},render:function(){(0,T.default)(!1)}});M.default=c,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){return!A||!A.__v2_compatible__}function i(A){return A&&A.getCurrentLocation}M.__esModule=!0;var T=Object.assign||function(A){for(var M=1;M=0&&0===window.sessionStorage.length)return;throw A}}function i(A){var M=void 0;try{M=window.sessionStorage.getItem(g(A))}catch(A){if(A.name===o)return null}if(M)try{return JSON.parse(M)}catch(A){}return null}M.__esModule=!0,M.saveState=e,M.readState=i;var T=t(23),E=(I(T),"@@History/"),N=["QuotaExceededError","QUOTA_EXCEEDED_ERR"],o="SecurityError"},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A){function M(A){return E.canUseDOM?void 0:T.default(!1),t.listen(A)}var t=n.default(e({getUserConfirmation:N.getUserConfirmation},A,{go:N.go}));return e({},t,{listen:M})}M.__esModule=!0;var e=Object.assign||function(A){for(var M=1;M1?M-1:0),e=1;e=A.childNodes.length?null:A.childNodes.item(t);A.insertBefore(M,I)}var g=t(434),e=t(220),i=t(17),T=t(76),E=t(121),N=t(2),o={dangerouslyReplaceNodeWithMarkup:g.dangerouslyReplaceNodeWithMarkup,updateTextContent:E,processUpdates:function(A,M){for(var t,i=null,o=null,n=0;n-1?void 0:i(!1),!N.plugins[t]){M.extractEvents?void 0:i(!1),N.plugins[t]=M;var I=M.eventTypes;for(var e in I)g(I[e],M,e)?void 0:i(!1)}}}function g(A,M,t){N.eventNameDispatchConfigs.hasOwnProperty(t)?i(!1):void 0,N.eventNameDispatchConfigs[t]=A;var I=A.phasedRegistrationNames;if(I){for(var g in I)if(I.hasOwnProperty(g)){var T=I[g];e(T,M,t)}return!0}return!!A.registrationName&&(e(A.registrationName,M,t),!0)}function e(A,M,t){N.registrationNameModules[A]?i(!1):void 0,N.registrationNameModules[A]=M,N.registrationNameDependencies[A]=M.eventTypes[t].dependencies}var i=t(2),T=null,E={},N={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},injectEventPluginOrder:function(A){T?i(!1):void 0,T=Array.prototype.slice.call(A),I()},injectEventPluginsByName:function(A){var M=!1;for(var t in A)if(A.hasOwnProperty(t)){var g=A[t];E.hasOwnProperty(t)&&E[t]===g||(E[t]?i(!1):void 0,E[t]=g,M=!0)}M&&I()},getPluginModuleForEvent:function(A){var M=A.dispatchConfig;if(M.registrationName)return N.registrationNameModules[M.registrationName]||null;for(var t in M.phasedRegistrationNames)if(M.phasedRegistrationNames.hasOwnProperty(t)){var I=N.registrationNameModules[M.phasedRegistrationNames[t]];if(I)return I}return null},_resetEventPlugins:function(){T=null;for(var A in E)E.hasOwnProperty(A)&&delete E[A];N.plugins.length=0;var M=N.eventNameDispatchConfigs;for(var t in M)M.hasOwnProperty(t)&&delete M[t];var I=N.registrationNameModules;for(var g in I)I.hasOwnProperty(g)&&delete I[g]}};A.exports=N},function(A,M,t){"use strict";function I(A){return(""+A).replace(x,"//")}function g(A,M){this.func=A,this.context=M,this.count=0}function e(A,M,t){var I=A.func,g=A.context;I.call(g,M,A.count++)}function i(A,M,t){if(null==A)return A;var I=g.getPooled(M,t);Q(A,e,I),g.release(I)}function T(A,M,t,I){this.result=A,this.keyPrefix=M,this.func=t,this.context=I,this.count=0}function E(A,M,t){var g=A.result,e=A.keyPrefix,i=A.func,T=A.context,E=i.call(T,M,A.count++);Array.isArray(E)?N(E,g,t,B.thatReturnsArgument):null!=E&&(a.isValidElement(E)&&(E=a.cloneAndReplaceKey(E,e+(E!==M?I(E.key||"")+"/":"")+t)),g.push(E))}function N(A,M,t,g,e){var i="";null!=t&&(i=I(t)+"/");var N=T.getPooled(M,i,g,e);Q(A,E,N),T.release(N)}function o(A,M,t){if(null==A)return A;var I=[];return N(A,I,null,M,t),I}function n(A,M,t){return null}function C(A,M){return Q(A,n,null)}function c(A){var M=[];return N(A,M,null,B.thatReturnsArgument),M}var D=t(31),a=t(13),B=t(20),Q=t(123),r=D.twoArgumentPooler,s=D.fourArgumentPooler,x=/\/(?!\/)/g;g.prototype.destructor=function(){this.func=null,this.context=null,this.count=0},D.addPoolingTo(g,r),T.prototype.destructor=function(){this.result=null,this.keyPrefix=null,this.func=null,this.context=null,this.count=0},D.addPoolingTo(T,s);var j={forEach:i,map:o,mapIntoWithKeyPrefixInternal:N,count:C,toArray:c};A.exports=j},function(A,M,t){"use strict";function I(A,M){var t=y.hasOwnProperty(M)?y[M]:null;w.hasOwnProperty(M)&&(t!==x.OVERRIDE_BASE?B(!1):void 0),A.hasOwnProperty(M)&&(t!==x.DEFINE_MANY&&t!==x.DEFINE_MANY_MERGED?B(!1):void 0)}function g(A,M){if(M){"function"==typeof M?B(!1):void 0,C.isValidElement(M)?B(!1):void 0;var t=A.prototype;M.hasOwnProperty(s)&&u.mixins(A,M.mixins);for(var g in M)if(M.hasOwnProperty(g)&&g!==s){var e=M[g];if(I(t,g),u.hasOwnProperty(g))u[g](A,e);else{var i=y.hasOwnProperty(g),N=t.hasOwnProperty(g),o="function"==typeof e,n=o&&!i&&!N&&M.autobind!==!1;if(n)t.__reactAutoBindMap||(t.__reactAutoBindMap={}),t.__reactAutoBindMap[g]=e,t[g]=e;else if(N){var c=y[g];!i||c!==x.DEFINE_MANY_MERGED&&c!==x.DEFINE_MANY?B(!1):void 0,c===x.DEFINE_MANY_MERGED?t[g]=T(t[g],e):c===x.DEFINE_MANY&&(t[g]=E(t[g],e))}else t[g]=e}}}}function e(A,M){if(M)for(var t in M){var I=M[t];if(M.hasOwnProperty(t)){var g=t in u;g?B(!1):void 0;var e=t in A;e?B(!1):void 0,A[t]=I}}}function i(A,M){A&&M&&"object"==typeof A&&"object"==typeof M?void 0:B(!1);for(var t in M)M.hasOwnProperty(t)&&(void 0!==A[t]?B(!1):void 0,A[t]=M[t]);return A}function T(A,M){return function(){var t=A.apply(this,arguments),I=M.apply(this,arguments);if(null==t)return I;if(null==I)return t;var g={};return i(g,t),i(g,I),g}}function E(A,M){return function(){A.apply(this,arguments),M.apply(this,arguments)}}function N(A,M){var t=M.bind(A);return t}function o(A){for(var M in A.__reactAutoBindMap)if(A.__reactAutoBindMap.hasOwnProperty(M)){var t=A.__reactAutoBindMap[M];A[M]=N(A,t)}}var n=t(207),C=t(13),c=(t(71),t(70),t(222)),D=t(4),a=t(50),B=t(2),Q=t(59),r=t(27),s=(t(3),r({mixins:null})),x=Q({DEFINE_ONCE:null,DEFINE_MANY:null,OVERRIDE_BASE:null,DEFINE_MANY_MERGED:null}),j=[],y={mixins:x.DEFINE_MANY,statics:x.DEFINE_MANY,propTypes:x.DEFINE_MANY,contextTypes:x.DEFINE_MANY,childContextTypes:x.DEFINE_MANY,getDefaultProps:x.DEFINE_MANY_MERGED,getInitialState:x.DEFINE_MANY_MERGED,getChildContext:x.DEFINE_MANY_MERGED,render:x.DEFINE_ONCE,componentWillMount:x.DEFINE_MANY,componentDidMount:x.DEFINE_MANY,componentWillReceiveProps:x.DEFINE_MANY,shouldComponentUpdate:x.DEFINE_ONCE,componentWillUpdate:x.DEFINE_MANY,componentDidUpdate:x.DEFINE_MANY,componentWillUnmount:x.DEFINE_MANY,updateComponent:x.OVERRIDE_BASE},u={displayName:function(A,M){A.displayName=M},mixins:function(A,M){if(M)for(var t=0;t"+T+""},receiveComponent:function(A,M){if(A!==this._currentElement){this._currentElement=A;var t=""+A;if(t!==this._stringText){this._stringText=t;var g=i.getNode(this._rootNodeID);I.updateTextContent(g,t)}}},unmountComponent:function(){e.unmountIDFromEnvironment(this._rootNodeID)}}),A.exports=o},function(A,M,t){"use strict";function I(){this.reinitializeTransaction()}var g=t(18),e=t(73),i=t(4),T=t(20),E={initialize:T,close:function(){C.isBatchingUpdates=!1}},N={initialize:T,close:g.flushBatchedUpdates.bind(g)},o=[N,E];i(I.prototype,e.Mixin,{getTransactionWrappers:function(){return o}});var n=new I,C={isBatchingUpdates:!1,batchedUpdates:function(A,M,t,I,g,e){var i=C.isBatchingUpdates;C.isBatchingUpdates=!0,i?A(M,t,I,g,e):n.perform(A,null,M,t,I,g,e)}};A.exports=C},function(A,M,t){"use strict";function I(){if(!L){L=!0,Q.EventEmitter.injectReactEventListener(B),Q.EventPluginHub.injectEventPluginOrder(T),Q.EventPluginHub.injectInstanceHandle(r),Q.EventPluginHub.injectMount(s),Q.EventPluginHub.injectEventPluginsByName({SimpleEventPlugin:u,EnterLeaveEventPlugin:E,ChangeEventPlugin:e,SelectEventPlugin:j,BeforeInputEventPlugin:g}),Q.NativeComponent.injectGenericComponentClass(D),Q.NativeComponent.injectTextComponentClass(a),Q.Class.injectMixin(n),Q.DOMProperty.injectDOMPropertyConfig(o),Q.DOMProperty.injectDOMPropertyConfig(w),Q.EmptyComponent.injectEmptyComponent("noscript"),Q.Updates.injectReconcileTransaction(x),Q.Updates.injectBatchingStrategy(c),Q.RootIndex.injectCreateReactRootIndex(N.canUseDOM?i.createReactRootIndex:y.createReactRootIndex),Q.Component.injectEnvironment(C)}}var g=t(430),e=t(432),i=t(433),T=t(435),E=t(436),N=t(10),o=t(439),n=t(441),C=t(109),c=t(212),D=t(445),a=t(211),B=t(453),Q=t(454),r=t(48),s=t(12),x=t(458),j=t(464),y=t(465),u=t(466),w=t(463),L=!1;A.exports={inject:I}},function(A,M,t){"use strict";function I(){if(n.current){var A=n.current.getName();if(A)return" Check the render method of ` + "`" + `"+A+"` + "`" + `."}return""}function g(A,M){if(A._store&&!A._store.validated&&null==A.key){A._store.validated=!0;e("uniqueKey",A,M)}}function e(A,M,t){var g=I();if(!g){var e="string"==typeof t?t:t.displayName||t.name;e&&(g=" Check the top-level render call using <"+e+">.")}var i=D[A]||(D[A]={});if(i[g])return null;i[g]=!0;var T={parentOrOwner:g,url:" See https://fb.me/react-warning-keys for more information.",childOwner:null};return M&&M._owner&&M._owner!==n.current&&(T.childOwner=" It was passed a child from "+M._owner.getName()+"."),T}function i(A,M){if("object"==typeof A)if(Array.isArray(A))for(var t=0;t/,e={CHECKSUM_ATTR_NAME:"data-react-checksum",addChecksumToMarkup:function(A){var M=I(A);return A.replace(g," "+e.CHECKSUM_ATTR_NAME+'="'+M+'"$&')},canReuseMarkup:function(A,M){var t=M.getAttribute(e.CHECKSUM_ATTR_NAME);t=t&&parseInt(t,10);var g=I(A);return g===t}};A.exports=e},function(A,M,t){"use strict";var I=t(59),g=I({INSERT_MARKUP:null,MOVE_EXISTING:null,REMOVE_NODE:null,SET_MARKUP:null,TEXT_CONTENT:null});A.exports=g},function(A,M,t){"use strict";function I(A){if("function"==typeof A.type)return A.type;var M=A.type,t=n[M];return null==t&&(n[M]=t=N(M)),t}function g(A){return o?void 0:E(!1),new o(A.type,A.props)}function e(A){return new C(A)}function i(A){return A instanceof C}var T=t(4),E=t(2),N=null,o=null,n={},C=null,c={injectGenericComponentClass:function(A){o=A},injectTextComponentClass:function(A){C=A},injectComponentClasses:function(A){T(n,A)}},D={getComponentClassForElement:I,createInternalComponent:g,createInstanceForText:e,isTextComponent:i,injection:c};A.exports=D},function(A,M,t){"use strict";function I(A,M){}var g=(t(3),{isMounted:function(A){return!1},enqueueCallback:function(A,M){},enqueueForceUpdate:function(A){I(A,"forceUpdate")},enqueueReplaceState:function(A,M){I(A,"replaceState")},enqueueSetState:function(A,M){I(A,"setState")},enqueueSetProps:function(A,M){I(A,"setProps")},enqueueReplaceProps:function(A,M){I(A,"replaceProps")}});A.exports=g},function(A,M,t){"use strict";function I(A){function M(M,t,I,g,e,i){if(g=g||y,i=i||I,null==t[I]){var T=s[e];return M?new Error("Required "+T+" ` + "`" + `"+i+"` + "`" + ` was not specified in "+("` + "`" + `"+g+"` + "`" + `.")):null}return A(t,I,g,e,i)}var t=M.bind(null,!1);return t.isRequired=M.bind(null,!0),t}function g(A){function M(M,t,I,g,e){var i=M[t],T=a(i);if(T!==A){var E=s[g],N=B(i);return new Error("Invalid "+E+" ` + "`" + `"+e+"` + "`" + ` of type "+("` + "`" + `"+N+"` + "`" + ` supplied to ` + "`" + `"+I+"` + "`" + `, expected ")+("` + "`" + `"+A+"` + "`" + `."))}return null}return I(M)}function e(){return I(x.thatReturns(null))}function i(A){function M(M,t,I,g,e){var i=M[t];if(!Array.isArray(i)){var T=s[g],E=a(i);return new Error("Invalid "+T+" ` + "`" + `"+e+"` + "`" + ` of type "+("` + "`" + `"+E+"` + "`" + ` supplied to ` + "`" + `"+I+"` + "`" + `, expected an array."))}for(var N=0;N>"}var r=t(13),s=t(70),x=t(20),j=t(118),y="<>",u={array:g("array"),bool:g("boolean"),func:g("function"),number:g("number"),object:g("object"),string:g("string"),any:e(),arrayOf:i,element:T(),instanceOf:E,node:C(),objectOf:o,oneOf:N,oneOfType:n,shape:c};A.exports=u},function(A,M){"use strict";var t={injectCreateReactRootIndex:function(A){I.createReactRootIndex=A}},I={createReactRootIndex:null,injection:t};A.exports=I},function(A,M){"use strict";var t={currentScrollLeft:0,currentScrollTop:0,refreshScrollValues:function(A){t.currentScrollLeft=A.x,t.currentScrollTop=A.y}};A.exports=t},function(A,M,t){"use strict";function I(A,M){if(null==M?g(!1):void 0,null==A)return M;var t=Array.isArray(A),I=Array.isArray(M);return t&&I?(A.push.apply(A,M),A):t?(A.push(M),A):I?[A].concat(M):[A,M]}var g=t(2);A.exports=I},function(A,M){"use strict";var t=function(A,M,t){Array.isArray(A)?A.forEach(M,t):A&&M.call(t,A)};A.exports=t},function(A,M,t){"use strict";function I(){return!e&&g.canUseDOM&&(e="textContent"in document.documentElement?"textContent":"innerText"),e}var g=t(10),e=null;A.exports=I},function(A,M){"use strict";function t(A){var M=A&&A.nodeName&&A.nodeName.toLowerCase();return M&&("input"===M&&I[A.type]||"textarea"===M)}var I={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0};A.exports=t},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(){for(var A=arguments.length,M=Array(A),t=0;t=0&&s.splice(M,1)}function T(A){var M=document.createElement("style");return M.type="text/css",e(A,M),M}function E(A){var M=document.createElement("link");return M.rel="stylesheet",e(A,M),M}function N(A,M){var t,I,g;if(M.singleton){var e=r++;t=Q||(Q=T(M)),I=o.bind(null,t,e,!1),g=o.bind(null,t,e,!0)}else A.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(t=E(M),I=C.bind(null,t),g=function(){i(t),t.href&&URL.revokeObjectURL(t.href)}):(t=T(M),I=n.bind(null,t),g=function(){i(t)});return I(A),function(M){if(M){if(M.css===A.css&&M.media===A.media&&M.sourceMap===A.sourceMap)return;I(A=M)}else g()}}function o(A,M,t,I){var g=t?"":I.css;if(A.styleSheet)A.styleSheet.cssText=x(M,g);else{var e=document.createTextNode(g),i=A.childNodes;i[M]&&A.removeChild(i[M]),i.length?A.insertBefore(e,i[M]):A.appendChild(e)}}function n(A,M){var t=M.css,I=M.media;if(I&&A.setAttribute("media",I),A.styleSheet)A.styleSheet.cssText=t;else{for(;A.firstChild;)A.removeChild(A.firstChild);A.appendChild(document.createTextNode(t))}}function C(A,M){var t=M.css,I=M.sourceMap;I&&(t+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(I))))+" */");var g=new Blob([t],{type:"text/css"}),e=A.href;A.href=URL.createObjectURL(g),e&&URL.revokeObjectURL(e)}var c={},D=function(A){var M;return function(){return"undefined"==typeof M&&(M=A.apply(this,arguments)),M}},a=D(function(){return/msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase())}),B=D(function(){return document.head||document.getElementsByTagName("head")[0]}),Q=null,r=0,s=[];A.exports=function(A,M){M=M||{},"undefined"==typeof M.singleton&&(M.singleton=a()),"undefined"==typeof M.insertAt&&(M.insertAt="bottom");var t=g(A);return I(t,M),function(A){for(var e=[],i=0;i",'"',"` + "`" + `"," ","\r","\n","\t"],D=["{","}","|","\\","^","` + "`" + `"].concat(c),a=["'"].concat(D),B=["%","/","?",";","#"].concat(a),Q=["/","?","#"],r=255,s=/^[+a-z0-9A-Z_-]{0,63}$/,x=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,j={javascript:!0,"javascript:":!0},y={javascript:!0,"javascript:":!0},u={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},w=t(360);I.prototype.parse=function(A,M,t){if(!N.isString(A))throw new TypeError("Parameter 'url' must be a string, not "+typeof A);var I=A.indexOf("?"),g=I!==-1&&I127?"x":O[F];if(!m.match(s)){var k=p.slice(0,Y),R=p.slice(Y+1),J=O.match(x);J&&(k.push(J[1]),R.unshift(J[2])),R.length&&(T="/"+R.join(".")+T),this.hostname=k.join(".");break}}}this.hostname.length>r?this.hostname="":this.hostname=this.hostname.toLowerCase(),z||(this.hostname=E.toASCII(this.hostname));var G=this.port?":"+this.port:"",H=this.hostname||"";this.host=H+G,this.href+=this.host,z&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==T[0]&&(T="/"+T))}if(!j[D])for(var Y=0,U=a.length;Y0)&&t.host.split("@");L&&(t.auth=L.shift(),t.host=t.hostname=L.shift())}return t.search=A.search,t.query=A.query,N.isNull(t.pathname)&&N.isNull(t.search)||(t.path=(t.pathname?t.pathname:"")+(t.search?t.search:"")),t.href=t.format(),t}if(!j.length)return t.pathname=null,t.search?t.path="/"+t.search:t.path=null,t.href=t.format(),t;for(var l=j.slice(-1)[0],Y=(t.host||A.host||j.length>1)&&("."===l||".."===l)||""===l,d=0,h=j.length;h>=0;h--)l=j[h],"."===l?j.splice(h,1):".."===l?(j.splice(h,1),d++):d&&(j.splice(h,1),d--);if(!s&&!x)for(;d--;d)j.unshift("..");!s||""===j[0]||j[0]&&"/"===j[0].charAt(0)||j.unshift(""),Y&&"/"!==j.join("/").substr(-1)&&j.push("");var S=""===j[0]||j[0]&&"/"===j[0].charAt(0);if(w){t.hostname=t.host=S?"":j.length?j.shift():"";var L=!!(t.host&&t.host.indexOf("@")>0)&&t.host.split("@");L&&(t.auth=L.shift(),t.host=t.hostname=L.shift())}return s=s||t.host&&j.length,s&&!S&&j.unshift(""),j.length?t.pathname=j.join("/"):(t.pathname=null,t.path=null),N.isNull(t.pathname)&&N.isNull(t.search)||(t.path=(t.pathname?t.pathname:"")+(t.search?t.search:"")),t.auth=A.auth||t.auth,t.slashes=t.slashes||A.slashes,t.href=t.format(),t},I.prototype.parseHost=function(){var A=this.host,M=n.exec(A);M&&(M=M[0],":"!==M&&(this.port=M.substr(1)),A=A.substr(0,A.length-M.length)),A&&(this.hostname=A)}},function(A,M){var t={animationIterationCount:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridColumn:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,stopOpacity:!0,strokeDashoffset:!0,strokeOpacity:!0,strokeWidth:!0};A.exports=function(A,M){return"number"!=typeof M||t[A]?M:M+"px"}},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M,t){return P.LoggedIn()?t():(location.pathname!==z.minioBrowserPrefix&&location.pathname!==z.minioBrowserPrefix+"/"||M(z.minioBrowserPrefix+"/login"),t())}function i(A,M){P.LoggedIn()&&M(""+z.minioBrowserPrefix)}function T(){q<2&&setTimeout(function(){document.querySelector(".page-load").classList.add("pl-"+q),q++,T()},K[q])}t(499);var E=t(1),N=g(E),o=t(16),n=g(o),C=t(485),c=g(C),D=t(125),a=g(D),B=t(230),Q=g(B),r=t(190),s=g(r),x=t(191),j=g(x),y=t(65),u=g(y),w=t(187),L=g(w),l=t(394),Y=g(l),d=t(22),h=g(d),S=t(42),z=(g(S),t(26)),p=t(19),U=I(p),O=t(255),m=g(O),F=t(245),f=g(F),k=t(241),R=g(k),J=t(498),G=(g(J),t(131)),H=g(G),b=t(60),X=g(b);window.Web=H.default;var v=(0,Q.default)(c.default)(a.default)(m.default),W=(0,h.default)(function(A){return A})(R.default),V=(0,h.default)(function(A){return A})(f.default),P=new H.default(window.location.protocol+"//"+window.location.host+z.minioBrowserPrefix+"/webrpc",v.dispatch);window.web=P,v.dispatch(U.setWeb(P));var Z=function(A){return N.default.createElement("div",null,A.children)};n.default.render(N.default.createElement(Y.default,{store:v,web:P},N.default.createElement(j.default,{history:u.default},N.default.createElement(s.default,{path:"/",component:Z},N.default.createElement(s.default,{path:"minio",component:Z},N.default.createElement(L.default,{component:W,onEnter:e}),N.default.createElement(s.default,{path:"login",component:V,onEnter:i}),N.default.createElement(s.default,{path:":bucket",component:W,onEnter:e}),N.default.createElement(s.default,{path:":bucket/*",component:W,onEnter:e}))))),document.getElementById("root"));var K=[0,400],q=0;T(),X.default.getItem("newlyUpdated")&&(v.dispatch(U.showAlert({type:"success",message:"Updated to the latest UI Version."})),X.default.removeItem("newlyUpdated"))},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){return A&&A.__esModule?A:{default:A}}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=function(){function A(A,M){for(var t=0;t-1})))}},{key:"listObjects",value:function(){var A=this.props.dispatch;A(eA.listObjects())}},{key:"selectPrefix",value:function(A,M){A.preventDefault();var t=this.props,I=(t.dispatch,t.currentPath),g=(t.web,t.currentBucket),e=encodeURI(M);if(M.endsWith("/")||""===M){if(M===I)return;D.default.push(TA.pathJoin(g,e))}else window.location=window.location.origin+"/minio/download/"+g+"/"+e+"?token="+DA.default.getItem("token")}},{key:"makeBucket",value:function(A){A.preventDefault();var M=this.refs.makeBucketRef.value;this.refs.makeBucketRef.value="";var t=this.props,I=t.web,g=t.dispatch;this.hideMakeBucketModal(),I.MakeBucket({bucketName:M}).then(function(){g(eA.addBucket(M)),g(eA.selectBucket(M))}).catch(function(A){return g(eA.showAlert({type:"danger",message:A.message}))})}},{key:"hideMakeBucketModal",value:function(){var A=this.props.dispatch;A(eA.hideMakeBucketModal())}},{key:"showMakeBucketModal",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showMakeBucketModal())}},{key:"showAbout",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showAbout())}},{key:"hideAbout",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.hideAbout())}},{key:"showBucketPolicy",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showBucketPolicy())}},{key:"hideBucketPolicy",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.hideBucketPolicy())}},{key:"uploadFile",value:function(A){A.preventDefault();var M=this.props,t=M.dispatch,I=M.buckets;if(0===I.length)return void t(eA.showAlert({type:"danger",message:"Bucket needs to be created before trying to upload files."}));var g=A.target.files[0];A.target.value=null,this.xhr=new XMLHttpRequest,t(eA.uploadFile(g,this.xhr))}},{key:"removeObject",value:function(){var A=this,M=this.props,t=M.web,I=M.dispatch,g=(M.currentPath,M.currentBucket),e=M.deleteConfirmation;t.RemoveObject({bucketName:g,objectName:e.object}).then(function(){A.hideDeleteConfirmation(),I(eA.removeObject(e.object))}).catch(function(A){return I(eA.showAlert({type:"danger",message:A.message}))})}},{key:"hideAlert",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.hideAlert())}},{key:"showDeleteConfirmation",value:function(A,M){A.preventDefault();var t=this.props.dispatch;t(eA.showDeleteConfirmation(M))}},{key:"hideDeleteConfirmation",value:function(){var A=this.props.dispatch;A(eA.hideDeleteConfirmation())}},{key:"shareObject",value:function(A,M){A.preventDefault();var t=this.props.dispatch;t(eA.shareObject(M))}},{key:"hideShareObjectModal",value:function(){var A=this.props.dispatch;A(eA.hideShareObject())}},{key:"dataType",value:function(A,M){return NA.getDataType(A,M)}},{key:"sortObjectsByName",value:function(A){var M=this.props,t=M.dispatch,I=M.objects,g=M.sortNameOrder;t(eA.setObjects(TA.sortObjectsByName(I,!g))),t(eA.setSortNameOrder(!g))}},{key:"sortObjectsBySize",value:function(){var A=this.props,M=A.dispatch,t=A.objects,I=A.sortSizeOrder;M(eA.setObjects(TA.sortObjectsBySize(t,!I))),M(eA.setSortSizeOrder(!I))}},{key:"sortObjectsByDate",value:function(){var A=this.props,M=A.dispatch,t=A.objects,I=A.sortDateOrder;M(eA.setObjects(TA.sortObjectsByDate(t,!I))),M(eA.setSortDateOrder(!I))}},{key:"logout",value:function(A){var M=this.props.web;A.preventDefault(),M.Logout(),D.default.push(oA.minioBrowserPrefix+"/login")}},{key:"fullScreen",value:function(A){A.preventDefault();var M=document.documentElement;M.requestFullscreen&&M.requestFullscreen(),M.mozRequestFullScreen&&M.mozRequestFullScreen(),M.webkitRequestFullscreen&&M.webkitRequestFullscreen(),M.msRequestFullscreen&&M.msRequestFullscreen()}},{key:"toggleSidebar",value:function(A){this.props.dispatch(eA.setSidebarStatus(A))}},{key:"hideSidebar",value:function(A){var M=A||window.event,t=M.srcElement||M.target;3===t.nodeType&&(t=t.parentNode);var I=t.id;"feh-trigger"!==I&&this.props.dispatch(eA.setSidebarStatus(!1))}},{key:"showSettings",value:function(A){A.preventDefault();var M=this.props.dispatch;M(eA.showSettings())}},{key:"showMessage",value:function(){var A=this.props.dispatch;A(eA.showAlert({type:"success",message:"Link copied to clipboard!"})),this.hideShareObjectModal()}},{key:"selectTexts",value:function(){this.refs.copyTextInput.select()}},{key:"handleExpireValue",value:function(A,M){M===-1?this.refs[A].stepDown(1):this.refs[A].stepUp(1),7==this.refs.expireDays.value&&(this.refs.expireHours.value=0,this.refs.expireMins.value=0)}},{key:"render",value:function(){var A=this.props.storageInfo,M=A.total,t=A.free,I=this.props,g=I.showMakeBucketModal,e=I.alert,i=I.sortNameOrder,T=I.sortSizeOrder,E=I.sortDateOrder,N=I.showAbout,n=I.showBucketPolicy,c=this.props.serverInfo,D=c.version,a=c.memory,Q=c.platform,r=c.runtime,x=this.props.sidebarStatus,y=this.props.showSettings,w=this.props,l=w.policies,d=w.currentBucket,S=(w.currentPath,this.props.deleteConfirmation),p=this.props.shareObject,U=this.props,O=U.web,F=U.prefixWritable,k=U.istruncated,J=y?o.default.createElement(V.default,null):o.default.createElement("noscript",null),H=o.default.createElement(L.default,{className:(0,C.default)({alert:!0,animated:!0,fadeInDown:e.show,fadeOutUp:!e.show}),bsStyle:e.type,onDismiss:this.hideAlert.bind(this)},o.default.createElement("div",{className:"text-center"},e.message));e.message||(H="");var X=(o.default.createElement(h.default,{id:"tt-sign-out"},"Sign out"),o.default.createElement(h.default,{id:"tt-upload-file"},"Upload file")),W=o.default.createElement(h.default,{id:"tt-create-bucket"},"Create bucket"),P="",K="",_="",AA=M-t,tA=AA/M*100+"%";O.LoggedIn()?K=o.default.createElement($.default,{fullScreenFunc:this.fullScreen.bind(this),aboutFunc:this.showAbout.bind(this),settingsFunc:this.showSettings.bind(this),logoutFunc:this.logout.bind(this)}):P=o.default.createElement("a",{className:"btn btn-danger",href:"/minio/login"},"Login"),O.LoggedIn()&&(_=o.default.createElement("div",{className:"feh-usage"},o.default.createElement("div",{className:"fehu-chart"},o.default.createElement("div",{style:{width:tA}})),o.default.createElement("ul",null,o.default.createElement("li",null,"Used:",B.default.filesize(M-t)),o.default.createElement("li",{className:"pull-right"},"Free:",B.default.filesize(M-AA)))));var gA="";return O.LoggedIn()?gA=o.default.createElement(z.default,{dropup:!0,className:"feb-actions",id:"fe-action-toggle"},o.default.createElement(z.default.Toggle,{noCaret:!0,className:"feba-toggle"},o.default.createElement("span",null,o.default.createElement("i",{className:"fa fa-plus"}))),o.default.createElement(z.default.Menu,null,o.default.createElement(Y.default,{placement:"left",overlay:X},o.default.createElement("a",{href:"#",className:"feba-btn feba-upload"},o.default.createElement("input",{type:"file",onChange:this.uploadFile.bind(this),style:{display:"none"},id:"file-input"}),o.default.createElement("label",{htmlFor:"file-input"}," ",o.default.createElement("i",{className:"fa fa-cloud-upload"})," "))),o.default.createElement(Y.default,{placement:"left",overlay:W},o.default.createElement("a",{href:"#",className:"feba-btn feba-bucket",onClick:this.showMakeBucketModal.bind(this)},o.default.createElement("i",{className:"fa fa-hdd-o"}))))):F&&(gA=o.default.createElement(z.default,{dropup:!0,className:"feb-actions",id:"fe-action-toggle"},o.default.createElement(z.default.Toggle,{noCaret:!0,className:"feba-toggle"},o.default.createElement("span",null,o.default.createElement("i",{className:"fa fa-plus"}))),o.default.createElement(z.default.Menu,null,o.default.createElement(Y.default,{placement:"left",overlay:X},o.default.createElement("a",{href:"#",className:"feba-btn feba-upload"},o.default.createElement("input",{type:"file",onChange:this.uploadFile.bind(this),style:{display:"none"},id:"file-input"}),o.default.createElement("label",{htmlFor:"file-input"}," ",o.default.createElement("i",{className:"fa fa-cloud-upload"})," ")))))),o.default.createElement("div",{className:(0,C.default)({"file-explorer":!0,toggled:x})},o.default.createElement(R.default,{searchBuckets:this.searchBuckets.bind(this),selectBucket:this.selectBucket.bind(this),clickOutside:this.hideSidebar.bind(this),showPolicy:this.showBucketPolicy.bind(this)}),o.default.createElement("div",{className:"fe-body"},o.default.createElement(m.default,null,H,o.default.createElement("header",{className:"fe-header-mobile hidden-lg hidden-md"},o.default.createElement("div",{id:"feh-trigger",className:"feh-trigger "+(0,C.default)({"feht-toggled":x}),onClick:this.toggleSidebar.bind(this,!x)},o.default.createElement("div",{className:"feht-lines"},o.default.createElement("div",{className:"top"}),o.default.createElement("div",{className:"center"}),o.default.createElement("div",{className:"bottom"}))),o.default.createElement("img",{className:"mh-logo",src:IA.default,alt:""})),o.default.createElement("header",{className:"fe-header"},o.default.createElement(G.default,{selectPrefix:this.selectPrefix.bind(this)}),_,o.default.createElement("ul",{className:"feh-actions"},o.default.createElement(b.default,null),P,K)),o.default.createElement("div",{className:"feb-container"},o.default.createElement("header",{className:"fesl-row","data-type":"folder"},o.default.createElement("div",{className:"fesl-item fi-name",onClick:this.sortObjectsByName.bind(this),"data-sort":"name"},"Name",o.default.createElement("i",{className:(0,C.default)({"fesli-sort":!0,fa:!0,"fa-sort-alpha-desc":i,"fa-sort-alpha-asc":!i})})),o.default.createElement("div",{className:"fesl-item fi-size",onClick:this.sortObjectsBySize.bind(this),"data-sort":"size"},"Size",o.default.createElement("i",{className:(0,C.default)({"fesli-sort":!0,fa:!0,"fa-sort-amount-desc":T,"fa-sort-amount-asc":!T})})),o.default.createElement("div",{className:"fesl-item fi-modified",onClick:this.sortObjectsByDate.bind(this),"data-sort":"last-modified"},"Last Modified",o.default.createElement("i",{className:(0,C.default)({"fesli-sort":!0,fa:!0,"fa-sort-numeric-desc":E,"fa-sort-numeric-asc":!E})})),o.default.createElement("div",{className:"fesl-item fi-actions"}))),o.default.createElement("div",{className:"feb-container"},o.default.createElement(BA.default,{loadMore:this.listObjects.bind(this),hasMore:k,useWindow:!0,initialLoad:!1},o.default.createElement(f.default,{dataType:this.dataType.bind(this),selectPrefix:this.selectPrefix.bind(this),showDeleteConfirmation:this.showDeleteConfirmation.bind(this),shareObject:this.shareObject.bind(this)})),o.default.createElement("div",{className:"text-center",style:{display:k?"block":"none"}},o.default.createElement("span",null,"Loading..."))),o.default.createElement(v.default,null),gA,o.default.createElement(s.default,{className:"modal-create-bucket",bsSize:"small",animation:!1,show:g,onHide:this.hideMakeBucketModal.bind(this)},o.default.createElement("button",{className:"close close-alt",onClick:this.hideMakeBucketModal.bind(this)},o.default.createElement("span",null,"×")),o.default.createElement(j.default,null,o.default.createElement("form",{onSubmit:this.makeBucket.bind(this)},o.default.createElement("div",{className:"input-group"},o.default.createElement("input",{className:"ig-text",type:"text",ref:"makeBucketRef",placeholder:"Bucket Name",autoFocus:!0}),o.default.createElement("i",{className:"ig-helpers"}))))),o.default.createElement(s.default,{className:"modal-about modal-dark",animation:!1,show:N,onHide:this.hideAbout.bind(this)},o.default.createElement("button",{className:"close",onClick:this.hideAbout.bind(this)},o.default.createElement("span",null,"×")),o.default.createElement("div",{className:"ma-inner"},o.default.createElement("div",{className:"mai-item hidden-xs"},o.default.createElement("a",{href:"https://minio.io",target:"_blank"},o.default.createElement("img",{className:"maii-logo",src:IA.default,alt:""}))),o.default.createElement("div",{className:"mai-item"},o.default.createElement("ul",{className:"maii-list"},o.default.createElement("li",null,o.default.createElement("div",null,"Version"),o.default.createElement("small",null,D)),o.default.createElement("li",null,o.default.createElement("div",null,"Memory"),o.default.createElement("small",null,a)),o.default.createElement("li",null,o.default.createElement("div",null,"Platform"),o.default.createElement("small",null,Q)),o.default.createElement("li",null,o.default.createElement("div",null,"Runtime"),o.default.createElement("small",null,r)))))),o.default.createElement(s.default,{className:"modal-policy",animation:!1,show:n,onHide:this.hideBucketPolicy.bind(this)},o.default.createElement(u.default,null,"Bucket Policy (",d,")",o.default.createElement("button",{className:"close close-alt",onClick:this.hideBucketPolicy.bind(this)},o.default.createElement("span",null,"×"))),o.default.createElement("div",{className:"pm-body"},o.default.createElement(Z.default,{bucket:d}),l.map(function(A,M){return o.default.createElement(q.default,{key:M,prefix:A.prefix,policy:A.policy})}))),o.default.createElement(MA.default,{show:S.show,icon:"fa fa-exclamation-triangle mci-red",text:"Are you sure you want to delete?",sub:"This cannot be undone!",okText:"Delete",cancelText:"Cancel",okHandler:this.removeObject.bind(this),cancelHandler:this.hideDeleteConfirmation.bind(this)}),o.default.createElement(s.default,{show:p.show,animation:!1,onHide:this.hideShareObjectModal.bind(this),bsSize:"small"},o.default.createElement(u.default,null,"Share Object"),o.default.createElement(j.default,null,o.default.createElement("div",{className:"input-group copy-text"},o.default.createElement("label",null,"Shareable Link"),o.default.createElement("input",{type:"text",ref:"copyTextInput",readOnly:"readOnly",value:window.location.protocol+"//"+p.url,onClick:this.selectTexts.bind(this)})),o.default.createElement("div",{className:"input-group",style:{display:O.LoggedIn()?"block":"none"}},o.default.createElement("label",null,"Expires in"),o.default.createElement("div",{className:"set-expire"},o.default.createElement("div",{className:"set-expire-item"},o.default.createElement("i",{className:"set-expire-increase",onClick:this.handleExpireValue.bind(this,"expireDays",1)}),o.default.createElement("div",{className:"set-expire-title"},"Days"),o.default.createElement("div",{className:"set-expire-value"},o.default.createElement("input",{ref:"expireDays",type:"number",min:0,max:7,defaultValue:0})),o.default.createElement("i",{className:"set-expire-decrease",onClick:this.handleExpireValue.bind(this,"expireDays",-1)})),o.default.createElement("div",{className:"set-expire-item"},o.default.createElement("i",{className:"set-expire-increase",onClick:this.handleExpireValue.bind(this,"expireHours",1)}),o.default.createElement("div",{className:"set-expire-title"},"Hours"),o.default.createElement("div",{className:"set-expire-value"},o.default.createElement("input",{ref:"expireHours",type:"number",min:0,max:24,defaultValue:0})),o.default.createElement("i",{className:"set-expire-decrease",onClick:this.handleExpireValue.bind(this,"expireHours",-1)})),o.default.createElement("div",{className:"set-expire-item"},o.default.createElement("i",{className:"set-expire-increase",onClick:this.handleExpireValue.bind(this,"expireMins",1)}),o.default.createElement("div",{className:"set-expire-title"},"Minutes"),o.default.createElement("div",{className:"set-expire-value"},o.default.createElement("input",{ref:"expireMins",type:"number",min:1,max:60,defaultValue:45})),o.default.createElement("i",{className:"set-expire-decrease",onClick:this.handleExpireValue.bind(this,"expireMins",-1)}))))),o.default.createElement("div",{className:"modal-footer"},o.default.createElement(CA.default,{text:p.url,onCopy:this.showMessage.bind(this)},o.default.createElement("button",{className:"btn btn-success"},"Copy Link")),o.default.createElement("button",{className:"btn btn-link",onClick:this.hideShareObjectModal.bind(this)},"Cancel"))),J)))}}]),M}(o.default.Component);M.default=QA},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var g=t(1),e=I(g),i=t(22),T=I(i),E=t(91),N=I(E),o=function(A){var M=A.fullScreenFunc,t=A.aboutFunc,I=A.settingsFunc,g=A.logoutFunc;return e.default.createElement("li",null,e.default.createElement(N.default,{pullRight:!0,id:"top-right-menu"},e.default.createElement(N.default.Toggle,{noCaret:!0},e.default.createElement("i",{className:"fa fa-reorder"})),e.default.createElement(N.default.Menu,{className:"dropdown-menu-right"},e.default.createElement("li",null,e.default.createElement("a",{target:"_blank",href:"https://github.com/minio/miniobrowser"},"Github ",e.default.createElement("i",{className:"fa fa-github"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:M},"Fullscreen ",e.default.createElement("i",{className:"fa fa-expand"}))),e.default.createElement("li",null,e.default.createElement("a",{target:"_blank",href:"https://docs.minio.io/"},"Documentation ",e.default.createElement("i",{className:"fa fa-book"}))),e.default.createElement("li",null,e.default.createElement("a",{target:"_blank",href:"https://slack.minio.io"},"Ask for help ",e.default.createElement("i",{className:"fa fa-question-circle"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:t},"About ",e.default.createElement("i",{className:"fa fa-info-circle"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:I},"Settings ",e.default.createElement("i",{className:"fa fa-cog"}))),e.default.createElement("li",null,e.default.createElement("a",{href:"",onClick:g},"Sign Out ",e.default.createElement("i",{className:"fa fa-sign-out"}))))))};M.default=(0,T.default)(function(A){return A})(o)},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var g=t(1),e=I(g),i=t(22),T=I(i),E=t(95),N=I(E),o=t(94),n=I(o),C=function(A){var M=A.latestUiVersion;return M===currentUiVersion?e.default.createElement("noscript",null):e.default.createElement("li",{className:"hidden-xs hidden-sm"},e.default.createElement("a",{href:""},e.default.createElement(n.default,{placement:"left",overlay:e.default.createElement(N.default,{id:"tt-version-update"},"New update available. Click to refresh.")}," ",e.default.createElement("i",{className:"fa fa-refresh"})," ")))};M.default=(0,T.default)(function(A){return{latestUiVersion:A.latestUiVersion}})(C)},function(A,M,t){"use strict";function I(A){if(A&&A.__esModule)return A;var M={};if(null!=A)for(var t in A)Object.prototype.hasOwnProperty.call(A,t)&&(M[t]=A[t]);return M.default=A,M}function g(A){ +return A&&A.__esModule?A:{default:A}}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=function(){function A(A,M){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{buckets:[],visibleBuckets:[],objects:[],istruncated:!0,storageInfo:{},serverInfo:{},currentBucket:"",currentPath:"",showMakeBucketModal:!1,uploads:{},alert:{show:!1,type:"danger",message:""},loginError:!1,sortNameOrder:!1,sortSizeOrder:!1,sortDateOrder:!1,latestUiVersion:currentUiVersion,sideBarActive:!1,loginRedirectPath:E.minioBrowserPrefix,settings:{accessKey:"",secretKey:"",secretKeyVisible:!1},showSettings:!1,policies:[],deleteConfirmation:{object:"",show:!1},shareObject:{show:!1,url:"",expiry:604800},prefixWritable:!1},M=arguments[1],t=Object.assign({},A);switch(M.type){case T.SET_WEB:t.web=M.web;break;case T.SET_BUCKETS:t.buckets=M.buckets;break;case T.ADD_BUCKET:t.buckets=[M.bucket].concat(e(t.buckets)),t.visibleBuckets=[M.bucket].concat(e(t.visibleBuckets));break;case T.SET_VISIBLE_BUCKETS:t.visibleBuckets=M.visibleBuckets;break;case T.SET_CURRENT_BUCKET:t.currentBucket=M.currentBucket;break;case T.SET_OBJECTS:M.objects.length?(t.objects=[].concat(e(t.objects),e(M.objects)),t.marker=M.marker,t.istruncated=M.istruncated):(t.objects=[],t.marker="",t.istruncated=M.istruncated);break;case T.SET_CURRENT_PATH:t.currentPath=M.currentPath;break;case T.SET_STORAGE_INFO:t.storageInfo=M.storageInfo;break;case T.SET_SERVER_INFO:t.serverInfo=M.serverInfo;break;case T.SHOW_MAKEBUCKET_MODAL:t.showMakeBucketModal=M.showMakeBucketModal;break;case T.UPLOAD_PROGRESS:t.uploads=Object.assign({},t.uploads),t.uploads[M.slug].loaded=M.loaded;break;case T.ADD_UPLOAD:t.uploads=Object.assign({},t.uploads,g({},M.slug,{loaded:0,size:M.size,xhr:M.xhr,name:M.name}));break;case T.STOP_UPLOAD:t.uploads=Object.assign({},t.uploads),delete t.uploads[M.slug];break;case T.SET_ALERT:t.alert.alertTimeout&&clearTimeout(t.alert.alertTimeout),M.alert.show?t.alert=M.alert:t.alert=Object.assign({},t.alert,{show:!1});break;case T.SET_LOGIN_ERROR:t.loginError=!0;break;case T.SET_SHOW_ABORT_MODAL:t.showAbortModal=M.showAbortModal;break;case T.SHOW_ABOUT:t.showAbout=M.showAbout;break;case T.SET_SORT_NAME_ORDER:t.sortNameOrder=M.sortNameOrder;break;case T.SET_SORT_SIZE_ORDER:t.sortSizeOrder=M.sortSizeOrder;break;case T.SET_SORT_DATE_ORDER:t.sortDateOrder=M.sortDateOrder;break;case T.SET_LATEST_UI_VERSION:t.latestUiVersion=M.latestUiVersion;break;case T.SET_SIDEBAR_STATUS:t.sidebarStatus=M.sidebarStatus;break;case T.SET_LOGIN_REDIRECT_PATH:t.loginRedirectPath=M.path;case T.SET_LOAD_BUCKET:t.loadBucket=M.loadBucket;break;case T.SET_LOAD_PATH:t.loadPath=M.loadPath;break;case T.SHOW_SETTINGS:t.showSettings=M.showSettings;break;case T.SET_SETTINGS:t.settings=Object.assign({},t.settings,M.settings);break;case T.SHOW_BUCKET_POLICY:t.showBucketPolicy=M.showBucketPolicy;break;case T.SET_POLICIES:t.policies=M.policies;break;case T.DELETE_CONFIRMATION:t.deleteConfirmation=Object.assign({},M.payload);break;case T.SET_SHARE_OBJECT:t.shareObject=Object.assign({},M.shareObject);break;case T.SET_PREFIX_WRITABLE:t.prefixWritable=M.prefixWritable;break;case T.REMOVE_OBJECT:var I=t.objects.findIndex(function(A){return A.name===M.object});if(I==-1)break;t.objects=[].concat(e(t.objects.slice(0,I)),e(t.objects.slice(I+1)))}return t}},function(A,M,t){A.exports={default:t(260),__esModule:!0}},function(A,M,t){t(270),A.exports=t(49).Object.assign},function(A,M,t){var I=t(80);A.exports=function(A,M){return I.create(A,M)}},function(A,M,t){t(271),A.exports=t(49).Object.keys},function(A,M,t){t(272),A.exports=t(49).Object.setPrototypeOf},function(A,M){A.exports=function(A){if("function"!=typeof A)throw TypeError(A+" is not a function!");return A}},function(A,M,t){var I=t(136);A.exports=function(A){if(!I(A))throw TypeError(A+" is not an object!");return A}},function(A,M){var t={}.toString;A.exports=function(A){return t.call(A).slice(8,-1)}},function(A,M){A.exports=function(A){if(void 0==A)throw TypeError("Can't call method on "+A);return A}},function(A,M){var t=A.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=t)},function(A,M,t){var I=t(263);A.exports=Object("z").propertyIsEnumerable(0)?Object:function(A){return"String"==I(A)?A.split(""):Object(A)}},function(A,M,t){var I=t(80),g=t(137),e=t(266);A.exports=t(135)(function(){var A=Object.assign,M={},t={},I=Symbol(),g="abcdefghijklmnopqrst";return M[I]=7,g.split("").forEach(function(A){t[A]=A}),7!=A({},M)[I]||Object.keys(A({},t)).join("")!=g})?function(A,M){for(var t=g(A),i=arguments,T=i.length,E=1,N=I.getKeys,o=I.getSymbols,n=I.isEnum;T>E;)for(var C,c=e(i[E++]),D=o?N(c).concat(o(c)):N(c),a=D.length,B=0;a>B;)n.call(c,C=D[B++])&&(t[C]=c[C]);return t}:Object.assign},function(A,M,t){var I=t(79),g=t(49),e=t(135);A.exports=function(A,M){var t=(g.Object||{})[A]||Object[A],i={};i[A]=M(t),I(I.S+I.F*e(function(){t(1)}),"Object",i)}},function(A,M,t){var I=t(80).getDesc,g=t(136),e=t(262),i=function(A,M){if(e(A),!g(M)&&null!==M)throw TypeError(M+": can't set as prototype!")};A.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(A,M,g){try{g=t(134)(Function.call,I(Object.prototype,"__proto__").set,2), +g(A,[]),M=!(A instanceof Array)}catch(A){M=!0}return function(A,t){return i(A,t),M?A.__proto__=t:g(A,t),A}}({},!1):void 0),check:i}},function(A,M,t){var I=t(79);I(I.S+I.F,"Object",{assign:t(267)})},function(A,M,t){var I=t(137);t(268)("keys",function(A){return function(M){return A(I(M))}})},function(A,M,t){var I=t(79);I(I.S,"Object",{setPrototypeOf:t(269).set})},function(A,M,t){function I(A){if(A)return g(A)}function g(A){for(var M in I.prototype)A[M]=I.prototype[M];return A}A.exports=I,I.prototype.on=I.prototype.addEventListener=function(A,M){return this._callbacks=this._callbacks||{},(this._callbacks["$"+A]=this._callbacks["$"+A]||[]).push(M),this},I.prototype.once=function(A,M){function t(){this.off(A,t),M.apply(this,arguments)}return t.fn=M,this.on(A,t),this},I.prototype.off=I.prototype.removeListener=I.prototype.removeAllListeners=I.prototype.removeEventListener=function(A,M){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var t=this._callbacks["$"+A];if(!t)return this;if(1==arguments.length)return delete this._callbacks["$"+A],this;for(var I,g=0;gli{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\\F000"}.fa-music:before{content:"\\F001"}.fa-search:before{content:"\\F002"}.fa-envelope-o:before{content:"\\F003"}.fa-heart:before{content:"\\F004"}.fa-star:before{content:"\\F005"}.fa-star-o:before{content:"\\F006"}.fa-user:before{content:"\\F007"}.fa-film:before{content:"\\F008"}.fa-th-large:before{content:"\\F009"}.fa-th:before{content:"\\F00A"}.fa-th-list:before{content:"\\F00B"}.fa-check:before{content:"\\F00C"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\\F00D"}.fa-search-plus:before{content:"\\F00E"}.fa-search-minus:before{content:"\\F010"}.fa-power-off:before{content:"\\F011"}.fa-signal:before{content:"\\F012"}.fa-cog:before,.fa-gear:before{content:"\\F013"}.fa-trash-o:before{content:"\\F014"}.fa-home:before{content:"\\F015"}.fa-file-o:before{content:"\\F016"}.fa-clock-o:before{content:"\\F017"}.fa-road:before{content:"\\F018"}.fa-download:before{content:"\\F019"}.fa-arrow-circle-o-down:before{content:"\\F01A"}.fa-arrow-circle-o-up:before{content:"\\F01B"}.fa-inbox:before{content:"\\F01C"}.fa-play-circle-o:before{content:"\\F01D"}.fa-repeat:before,.fa-rotate-right:before{content:"\\F01E"}.fa-refresh:before{content:"\\F021"}.fa-list-alt:before{content:"\\F022"}.fa-lock:before{content:"\\F023"}.fa-flag:before{content:"\\F024"}.fa-headphones:before{content:"\\F025"}.fa-volume-off:before{content:"\\F026"}.fa-volume-down:before{content:"\\F027"}.fa-volume-up:before{content:"\\F028"}.fa-qrcode:before{content:"\\F029"}.fa-barcode:before{content:"\\F02A"}.fa-tag:before{content:"\\F02B"}.fa-tags:before{content:"\\F02C"}.fa-book:before{content:"\\F02D"}.fa-bookmark:before{content:"\\F02E"}.fa-print:before{content:"\\F02F"}.fa-camera:before{content:"\\F030"}.fa-font:before{content:"\\F031"}.fa-bold:before{content:"\\F032"}.fa-italic:before{content:"\\F033"}.fa-text-height:before{content:"\\F034"}.fa-text-width:before{content:"\\F035"}.fa-align-left:before{content:"\\F036"}.fa-align-center:before{content:"\\F037"}.fa-align-right:before{content:"\\F038"}.fa-align-justify:before{content:"\\F039"}.fa-list:before{content:"\\F03A"}.fa-dedent:before,.fa-outdent:before{content:"\\F03B"}.fa-indent:before{content:"\\F03C"}.fa-video-camera:before{content:"\\F03D"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\\F03E"}.fa-pencil:before{content:"\\F040"}.fa-map-marker:before{content:"\\F041"}.fa-adjust:before{content:"\\F042"}.fa-tint:before{content:"\\F043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\\F044"}.fa-share-square-o:before{content:"\\F045"}.fa-check-square-o:before{content:"\\F046"}.fa-arrows:before{content:"\\F047"}.fa-step-backward:before{content:"\\F048"}.fa-fast-backward:before{content:"\\F049"}.fa-backward:before{content:"\\F04A"}.fa-play:before{content:"\\F04B"}.fa-pause:before{content:"\\F04C"}.fa-stop:before{content:"\\F04D"}.fa-forward:before{content:"\\F04E"}.fa-fast-forward:before{content:"\\F050"}.fa-step-forward:before{content:"\\F051"}.fa-eject:before{content:"\\F052"}.fa-chevron-left:before{content:"\\F053"}.fa-chevron-right:before{content:"\\F054"}.fa-plus-circle:before{content:"\\F055"}.fa-minus-circle:before{content:"\\F056"}.fa-times-circle:before{content:"\\F057"}.fa-check-circle:before{content:"\\F058"}.fa-question-circle:before{content:"\\F059"}.fa-info-circle:before{content:"\\F05A"}.fa-crosshairs:before{content:"\\F05B"}.fa-times-circle-o:before{content:"\\F05C"}.fa-check-circle-o:before{content:"\\F05D"}.fa-ban:before{content:"\\F05E"}.fa-arrow-left:before{content:"\\F060"}.fa-arrow-right:before{content:"\\F061"}.fa-arrow-up:before{content:"\\F062"}.fa-arrow-down:before{content:"\\F063"}.fa-mail-forward:before,.fa-share:before{content:"\\F064"}.fa-expand:before{content:"\\F065"}.fa-compress:before{content:"\\F066"}.fa-plus:before{content:"\\F067"}.fa-minus:before{content:"\\F068"}.fa-asterisk:before{content:"\\F069"}.fa-exclamation-circle:before{content:"\\F06A"}.fa-gift:before{content:"\\F06B"}.fa-leaf:before{content:"\\F06C"}.fa-fire:before{content:"\\F06D"}.fa-eye:before{content:"\\F06E"}.fa-eye-slash:before{content:"\\F070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\\F071"}.fa-plane:before{content:"\\F072"}.fa-calendar:before{content:"\\F073"}.fa-random:before{content:"\\F074"}.fa-comment:before{content:"\\F075"}.fa-magnet:before{content:"\\F076"}.fa-chevron-up:before{content:"\\F077"}.fa-chevron-down:before{content:"\\F078"}.fa-retweet:before{content:"\\F079"}.fa-shopping-cart:before{content:"\\F07A"}.fa-folder:before{content:"\\F07B"}.fa-folder-open:before{content:"\\F07C"}.fa-arrows-v:before{content:"\\F07D"}.fa-arrows-h:before{content:"\\F07E"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\\F080"}.fa-twitter-square:before{content:"\\F081"}.fa-facebook-square:before{content:"\\F082"}.fa-camera-retro:before{content:"\\F083"}.fa-key:before{content:"\\F084"}.fa-cogs:before,.fa-gears:before{content:"\\F085"}.fa-comments:before{content:"\\F086"}.fa-thumbs-o-up:before{content:"\\F087"}.fa-thumbs-o-down:before{content:"\\F088"}.fa-star-half:before{content:"\\F089"}.fa-heart-o:before{content:"\\F08A"}.fa-sign-out:before{content:"\\F08B"}.fa-linkedin-square:before{content:"\\F08C"}.fa-thumb-tack:before{content:"\\F08D"}.fa-external-link:before{content:"\\F08E"}.fa-sign-in:before{content:"\\F090"}.fa-trophy:before{content:"\\F091"}.fa-github-square:before{content:"\\F092"}.fa-upload:before{content:"\\F093"}.fa-lemon-o:before{content:"\\F094"}.fa-phone:before{content:"\\F095"}.fa-square-o:before{content:"\\F096"}.fa-bookmark-o:before{content:"\\F097"}.fa-phone-square:before{content:"\\F098"}.fa-twitter:before{content:"\\F099"}.fa-facebook-f:before,.fa-facebook:before{content:"\\F09A"}.fa-github:before{content:"\\F09B"}.fa-unlock:before{content:"\\F09C"}.fa-credit-card:before{content:"\\F09D"}.fa-feed:before,.fa-rss:before{content:"\\F09E"}.fa-hdd-o:before{content:"\\F0A0"}.fa-bullhorn:before{content:"\\F0A1"}.fa-bell:before{content:"\\F0F3"}.fa-certificate:before{content:"\\F0A3"}.fa-hand-o-right:before{content:"\\F0A4"}.fa-hand-o-left:before{content:"\\F0A5"}.fa-hand-o-up:before{content:"\\F0A6"}.fa-hand-o-down:before{content:"\\F0A7"}.fa-arrow-circle-left:before{content:"\\F0A8"}.fa-arrow-circle-right:before{content:"\\F0A9"}.fa-arrow-circle-up:before{content:"\\F0AA"}.fa-arrow-circle-down:before{content:"\\F0AB"}.fa-globe:before{content:"\\F0AC"}.fa-wrench:before{content:"\\F0AD"}.fa-tasks:before{content:"\\F0AE"}.fa-filter:before{content:"\\F0B0"}.fa-briefcase:before{content:"\\F0B1"}.fa-arrows-alt:before{content:"\\F0B2"}.fa-group:before,.fa-users:before{content:"\\F0C0"}.fa-chain:before,.fa-link:before{content:"\\F0C1"}.fa-cloud:before{content:"\\F0C2"}.fa-flask:before{content:"\\F0C3"}.fa-cut:before,.fa-scissors:before{content:"\\F0C4"}.fa-copy:before,.fa-files-o:before{content:"\\F0C5"}.fa-paperclip:before{content:"\\F0C6"}.fa-floppy-o:before,.fa-save:before{content:"\\F0C7"}.fa-square:before{content:"\\F0C8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\\F0C9"}.fa-list-ul:before{content:"\\F0CA"}.fa-list-ol:before{content:"\\F0CB"}.fa-strikethrough:before{content:"\\F0CC"}.fa-underline:before{content:"\\F0CD"}.fa-table:before{content:"\\F0CE"}.fa-magic:before{content:"\\F0D0"}.fa-truck:before{content:"\\F0D1"}.fa-pinterest:before{content:"\\F0D2"}.fa-pinterest-square:before{content:"\\F0D3"}.fa-google-plus-square:before{content:"\\F0D4"}.fa-google-plus:before{content:"\\F0D5"}.fa-money:before{content:"\\F0D6"}.fa-caret-down:before{content:"\\F0D7"}.fa-caret-up:before{content:"\\F0D8"}.fa-caret-left:before{content:"\\F0D9"}.fa-caret-right:before{content:"\\F0DA"}.fa-columns:before{content:"\\F0DB"}.fa-sort:before,.fa-unsorted:before{content:"\\F0DC"}.fa-sort-desc:before,.fa-sort-down:before{content:"\\F0DD"}.fa-sort-asc:before,.fa-sort-up:before{content:"\\F0DE"}.fa-envelope:before{content:"\\F0E0"}.fa-linkedin:before{content:"\\F0E1"}.fa-rotate-left:before,.fa-undo:before{content:"\\F0E2"}.fa-gavel:before,.fa-legal:before{content:"\\F0E3"}.fa-dashboard:before,.fa-tachometer:before{content:"\\F0E4"}.fa-comment-o:before{content:"\\F0E5"}.fa-comments-o:before{content:"\\F0E6"}.fa-bolt:before,.fa-flash:before{content:"\\F0E7"}.fa-sitemap:before{content:"\\F0E8"}.fa-umbrella:before{content:"\\F0E9"}.fa-clipboard:before,.fa-paste:before{content:"\\F0EA"}.fa-lightbulb-o:before{content:"\\F0EB"}.fa-exchange:before{content:"\\F0EC"}.fa-cloud-download:before{content:"\\F0ED"}.fa-cloud-upload:before{content:"\\F0EE"}.fa-user-md:before{content:"\\F0F0"}.fa-stethoscope:before{content:"\\F0F1"}.fa-suitcase:before{content:"\\F0F2"}.fa-bell-o:before{content:"\\F0A2"}.fa-coffee:before{content:"\\F0F4"}.fa-cutlery:before{content:"\\F0F5"}.fa-file-text-o:before{content:"\\F0F6"}.fa-building-o:before{content:"\\F0F7"}.fa-hospital-o:before{content:"\\F0F8"}.fa-ambulance:before{content:"\\F0F9"}.fa-medkit:before{content:"\\F0FA"}.fa-fighter-jet:before{content:"\\F0FB"}.fa-beer:before{content:"\\F0FC"}.fa-h-square:before{content:"\\F0FD"}.fa-plus-square:before{content:"\\F0FE"}.fa-angle-double-left:before{content:"\\F100"}.fa-angle-double-right:before{content:"\\F101"}.fa-angle-double-up:before{content:"\\F102"}.fa-angle-double-down:before{content:"\\F103"}.fa-angle-left:before{content:"\\F104"}.fa-angle-right:before{content:"\\F105"}.fa-angle-up:before{content:"\\F106"}.fa-angle-down:before{content:"\\F107"}.fa-desktop:before{content:"\\F108"}.fa-laptop:before{content:"\\F109"}.fa-tablet:before{content:"\\F10A"}.fa-mobile-phone:before,.fa-mobile:before{content:"\\F10B"}.fa-circle-o:before{content:"\\F10C"}.fa-quote-left:before{content:"\\F10D"}.fa-quote-right:before{content:"\\F10E"}.fa-spinner:before{content:"\\F110"}.fa-circle:before{content:"\\F111"}.fa-mail-reply:before,.fa-reply:before{content:"\\F112"}.fa-github-alt:before{content:"\\F113"}.fa-folder-o:before{content:"\\F114"}.fa-folder-open-o:before{content:"\\F115"}.fa-smile-o:before{content:"\\F118"}.fa-frown-o:before{content:"\\F119"}.fa-meh-o:before{content:"\\F11A"}.fa-gamepad:before{content:"\\F11B"}.fa-keyboard-o:before{content:"\\F11C"}.fa-flag-o:before{content:"\\F11D"}.fa-flag-checkered:before{content:"\\F11E"}.fa-terminal:before{content:"\\F120"}.fa-code:before{content:"\\F121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\\F122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\\F123"}.fa-location-arrow:before{content:"\\F124"}.fa-crop:before{content:"\\F125"}.fa-code-fork:before{content:"\\F126"}.fa-chain-broken:before,.fa-unlink:before{content:"\\F127"}.fa-question:before{content:"\\F128"}.fa-info:before{content:"\\F129"}.fa-exclamation:before{content:"\\F12A"}.fa-superscript:before{content:"\\F12B"}.fa-subscript:before{content:"\\F12C"}.fa-eraser:before{content:"\\F12D"}.fa-puzzle-piece:before{content:"\\F12E"}.fa-microphone:before{content:"\\F130"}.fa-microphone-slash:before{content:"\\F131"}.fa-shield:before{content:"\\F132"}.fa-calendar-o:before{content:"\\F133"}.fa-fire-extinguisher:before{content:"\\F134"}.fa-rocket:before{content:"\\F135"}.fa-maxcdn:before{content:"\\F136"}.fa-chevron-circle-left:before{content:"\\F137"}.fa-chevron-circle-right:before{content:"\\F138"}.fa-chevron-circle-up:before{content:"\\F139"}.fa-chevron-circle-down:before{content:"\\F13A"}.fa-html5:before{content:"\\F13B"}.fa-css3:before{content:"\\F13C"}.fa-anchor:before{content:"\\F13D"}.fa-unlock-alt:before{content:"\\F13E"}.fa-bullseye:before{content:"\\F140"}.fa-ellipsis-h:before{content:"\\F141"}.fa-ellipsis-v:before{content:"\\F142"}.fa-rss-square:before{content:"\\F143"}.fa-play-circle:before{content:"\\F144"}.fa-ticket:before{content:"\\F145"}.fa-minus-square:before{content:"\\F146"}.fa-minus-square-o:before{content:"\\F147"}.fa-level-up:before{content:"\\F148"}.fa-level-down:before{content:"\\F149"}.fa-check-square:before{content:"\\F14A"}.fa-pencil-square:before{content:"\\F14B"}.fa-external-link-square:before{content:"\\F14C"}.fa-share-square:before{content:"\\F14D"}.fa-compass:before{content:"\\F14E"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\\F150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\\F151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\\F152"}.fa-eur:before,.fa-euro:before{content:"\\F153"}.fa-gbp:before{content:"\\F154"}.fa-dollar:before,.fa-usd:before{content:"\\F155"}.fa-inr:before,.fa-rupee:before{content:"\\F156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\\F157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\\F158"}.fa-krw:before,.fa-won:before{content:"\\F159"}.fa-bitcoin:before,.fa-btc:before{content:"\\F15A"}.fa-file:before{content:"\\F15B"}.fa-file-text:before{content:"\\F15C"}.fa-sort-alpha-asc:before{content:"\\F15D"}.fa-sort-alpha-desc:before{content:"\\F15E"}.fa-sort-amount-asc:before{content:"\\F160"}.fa-sort-amount-desc:before{content:"\\F161"}.fa-sort-numeric-asc:before{content:"\\F162"}.fa-sort-numeric-desc:before{content:"\\F163"}.fa-thumbs-up:before{content:"\\F164"}.fa-thumbs-down:before{content:"\\F165"}.fa-youtube-square:before{content:"\\F166"}.fa-youtube:before{content:"\\F167"}.fa-xing:before{content:"\\F168"}.fa-xing-square:before{content:"\\F169"}.fa-youtube-play:before{content:"\\F16A"}.fa-dropbox:before{content:"\\F16B"}.fa-stack-overflow:before{content:"\\F16C"}.fa-instagram:before{content:"\\F16D"}.fa-flickr:before{content:"\\F16E"}.fa-adn:before{content:"\\F170"}.fa-bitbucket:before{content:"\\F171"}.fa-bitbucket-square:before{content:"\\F172"}.fa-tumblr:before{content:"\\F173"}.fa-tumblr-square:before{content:"\\F174"}.fa-long-arrow-down:before{content:"\\F175"}.fa-long-arrow-up:before{content:"\\F176"}.fa-long-arrow-left:before{content:"\\F177"}.fa-long-arrow-right:before{content:"\\F178"}.fa-apple:before{content:"\\F179"}.fa-windows:before{content:"\\F17A"}.fa-android:before{content:"\\F17B"}.fa-linux:before{content:"\\F17C"}.fa-dribbble:before{content:"\\F17D"}.fa-skype:before{content:"\\F17E"}.fa-foursquare:before{content:"\\F180"}.fa-trello:before{content:"\\F181"}.fa-female:before{content:"\\F182"}.fa-male:before{content:"\\F183"}.fa-gittip:before,.fa-gratipay:before{content:"\\F184"}.fa-sun-o:before{content:"\\F185"}.fa-moon-o:before{content:"\\F186"}.fa-archive:before{content:"\\F187"}.fa-bug:before{content:"\\F188"}.fa-vk:before{content:"\\F189"}.fa-weibo:before{content:"\\F18A"}.fa-renren:before{content:"\\F18B"}.fa-pagelines:before{content:"\\F18C"}.fa-stack-exchange:before{content:"\\F18D"}.fa-arrow-circle-o-right:before{content:"\\F18E"}.fa-arrow-circle-o-left:before{content:"\\F190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\\F191"}.fa-dot-circle-o:before{content:"\\F192"}.fa-wheelchair:before{content:"\\F193"}.fa-vimeo-square:before{content:"\\F194"}.fa-try:before,.fa-turkish-lira:before{content:"\\F195"}.fa-plus-square-o:before{content:"\\F196"}.fa-space-shuttle:before{content:"\\F197"}.fa-slack:before{content:"\\F198"}.fa-envelope-square:before{content:"\\F199"}.fa-wordpress:before{content:"\\F19A"}.fa-openid:before{content:"\\F19B"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\\F19C"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\\F19D"}.fa-yahoo:before{content:"\\F19E"}.fa-google:before{content:"\\F1A0"}.fa-reddit:before{content:"\\F1A1"}.fa-reddit-square:before{content:"\\F1A2"}.fa-stumbleupon-circle:before{content:"\\F1A3"}.fa-stumbleupon:before{content:"\\F1A4"}.fa-delicious:before{content:"\\F1A5"}.fa-digg:before{content:"\\F1A6"}.fa-pied-piper-pp:before{content:"\\F1A7"}.fa-pied-piper-alt:before{content:"\\F1A8"}.fa-drupal:before{content:"\\F1A9"}.fa-joomla:before{content:"\\F1AA"}.fa-language:before{content:"\\F1AB"}.fa-fax:before{content:"\\F1AC"}.fa-building:before{content:"\\F1AD"}.fa-child:before{content:"\\F1AE"}.fa-paw:before{content:"\\F1B0"}.fa-spoon:before{content:"\\F1B1"}.fa-cube:before{content:"\\F1B2"}.fa-cubes:before{content:"\\F1B3"}.fa-behance:before{content:"\\F1B4"}.fa-behance-square:before{content:"\\F1B5"}.fa-steam:before{content:"\\F1B6"}.fa-steam-square:before{content:"\\F1B7"}.fa-recycle:before{content:"\\F1B8"}.fa-automobile:before,.fa-car:before{content:"\\F1B9"}.fa-cab:before,.fa-taxi:before{content:"\\F1BA"}.fa-tree:before{content:"\\F1BB"}.fa-spotify:before{content:"\\F1BC"}.fa-deviantart:before{content:"\\F1BD"}.fa-soundcloud:before{content:"\\F1BE"}.fa-database:before{content:"\\F1C0"}.fa-file-pdf-o:before{content:"\\F1C1"}.fa-file-word-o:before{content:"\\F1C2"}.fa-file-excel-o:before{content:"\\F1C3"}.fa-file-powerpoint-o:before{content:"\\F1C4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\\F1C5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\\F1C6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\\F1C7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\\F1C8"}.fa-file-code-o:before{content:"\\F1C9"}.fa-vine:before{content:"\\F1CA"}.fa-codepen:before{content:"\\F1CB"}.fa-jsfiddle:before{content:"\\F1CC"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\\F1CD"}.fa-circle-o-notch:before{content:"\\F1CE"}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:"\\F1D0"}.fa-empire:before,.fa-ge:before{content:"\\F1D1"}.fa-git-square:before{content:"\\F1D2"}.fa-git:before{content:"\\F1D3"}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:"\\F1D4"}.fa-tencent-weibo:before{content:"\\F1D5"}.fa-qq:before{content:"\\F1D6"}.fa-wechat:before,.fa-weixin:before{content:"\\F1D7"}.fa-paper-plane:before,.fa-send:before{content:"\\F1D8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\\F1D9"}.fa-history:before{content:"\\F1DA"}.fa-circle-thin:before{content:"\\F1DB"}.fa-header:before{content:"\\F1DC"}.fa-paragraph:before{content:"\\F1DD"}.fa-sliders:before{content:"\\F1DE"}.fa-share-alt:before{content:"\\F1E0"}.fa-share-alt-square:before{content:"\\F1E1"}.fa-bomb:before{content:"\\F1E2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\\F1E3"}.fa-tty:before{content:"\\F1E4"}.fa-binoculars:before{content:"\\F1E5"}.fa-plug:before{content:"\\F1E6"}.fa-slideshare:before{content:"\\F1E7"}.fa-twitch:before{content:"\\F1E8"}.fa-yelp:before{content:"\\F1E9"}.fa-newspaper-o:before{content:"\\F1EA"}.fa-wifi:before{content:"\\F1EB"}.fa-calculator:before{content:"\\F1EC"}.fa-paypal:before{content:"\\F1ED"}.fa-google-wallet:before{content:"\\F1EE"}.fa-cc-visa:before{content:"\\F1F0"}.fa-cc-mastercard:before{content:"\\F1F1"}.fa-cc-discover:before{content:"\\F1F2"}.fa-cc-amex:before{content:"\\F1F3"}.fa-cc-paypal:before{content:"\\F1F4"}.fa-cc-stripe:before{content:"\\F1F5"}.fa-bell-slash:before{content:"\\F1F6"}.fa-bell-slash-o:before{content:"\\F1F7"}.fa-trash:before{content:"\\F1F8"}.fa-copyright:before{content:"\\F1F9"}.fa-at:before{content:"\\F1FA"}.fa-eyedropper:before{content:"\\F1FB"}.fa-paint-brush:before{content:"\\F1FC"}.fa-birthday-cake:before{content:"\\F1FD"}.fa-area-chart:before{content:"\\F1FE"}.fa-pie-chart:before{content:"\\F200"}.fa-line-chart:before{content:"\\F201"}.fa-lastfm:before{content:"\\F202"}.fa-lastfm-square:before{content:"\\F203"}.fa-toggle-off:before{content:"\\F204"}.fa-toggle-on:before{content:"\\F205"}.fa-bicycle:before{content:"\\F206"}.fa-bus:before{content:"\\F207"}.fa-ioxhost:before{content:"\\F208"}.fa-angellist:before{content:"\\F209"}.fa-cc:before{content:"\\F20A"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\\F20B"}.fa-meanpath:before{content:"\\F20C"}.fa-buysellads:before{content:"\\F20D"}.fa-connectdevelop:before{content:"\\F20E"}.fa-dashcube:before{content:"\\F210"}.fa-forumbee:before{content:"\\F211"}.fa-leanpub:before{content:"\\F212"}.fa-sellsy:before{content:"\\F213"}.fa-shirtsinbulk:before{content:"\\F214"}.fa-simplybuilt:before{content:"\\F215"}.fa-skyatlas:before{content:"\\F216"}.fa-cart-plus:before{content:"\\F217"}.fa-cart-arrow-down:before{content:"\\F218"}.fa-diamond:before{content:"\\F219"}.fa-ship:before{content:"\\F21A"}.fa-user-secret:before{content:"\\F21B"}.fa-motorcycle:before{content:"\\F21C"}.fa-street-view:before{content:"\\F21D"}.fa-heartbeat:before{content:"\\F21E"}.fa-venus:before{content:"\\F221"}.fa-mars:before{content:"\\F222"}.fa-mercury:before{content:"\\F223"}.fa-intersex:before,.fa-transgender:before{content:"\\F224"}.fa-transgender-alt:before{content:"\\F225"}.fa-venus-double:before{content:"\\F226"}.fa-mars-double:before{content:"\\F227"}.fa-venus-mars:before{content:"\\F228"}.fa-mars-stroke:before{content:"\\F229"}.fa-mars-stroke-v:before{content:"\\F22A"}.fa-mars-stroke-h:before{content:"\\F22B"}.fa-neuter:before{content:"\\F22C"}.fa-genderless:before{content:"\\F22D"}.fa-facebook-official:before{content:"\\F230"}.fa-pinterest-p:before{content:"\\F231"}.fa-whatsapp:before{content:"\\F232"}.fa-server:before{content:"\\F233"}.fa-user-plus:before{content:"\\F234"}.fa-user-times:before{content:"\\F235"}.fa-bed:before,.fa-hotel:before{content:"\\F236"}.fa-viacoin:before{content:"\\F237"}.fa-train:before{content:"\\F238"}.fa-subway:before{content:"\\F239"}.fa-medium:before{content:"\\F23A"}.fa-y-combinator:before,.fa-yc:before{content:"\\F23B"}.fa-optin-monster:before{content:"\\F23C"}.fa-opencart:before{content:"\\F23D"}.fa-expeditedssl:before{content:"\\F23E"}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:"\\F240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\\F241"}.fa-battery-2:before,.fa-battery-half:before{content:"\\F242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\\F243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\\F244"}.fa-mouse-pointer:before{content:"\\F245"}.fa-i-cursor:before{content:"\\F246"}.fa-object-group:before{content:"\\F247"}.fa-object-ungroup:before{content:"\\F248"}.fa-sticky-note:before{content:"\\F249"}.fa-sticky-note-o:before{content:"\\F24A"}.fa-cc-jcb:before{content:"\\F24B"}.fa-cc-diners-club:before{content:"\\F24C"}.fa-clone:before{content:"\\F24D"}.fa-balance-scale:before{content:"\\F24E"}.fa-hourglass-o:before{content:"\\F250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\\F251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\\F252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\\F253"}.fa-hourglass:before{content:"\\F254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\\F255"}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:"\\F256"}.fa-hand-scissors-o:before{content:"\\F257"}.fa-hand-lizard-o:before{content:"\\F258"}.fa-hand-spock-o:before{content:"\\F259"}.fa-hand-pointer-o:before{content:"\\F25A"}.fa-hand-peace-o:before{content:"\\F25B"}.fa-trademark:before{content:"\\F25C"}.fa-registered:before{content:"\\F25D"}.fa-creative-commons:before{content:"\\F25E"}.fa-gg:before{content:"\\F260"}.fa-gg-circle:before{content:"\\F261"}.fa-tripadvisor:before{content:"\\F262"}.fa-odnoklassniki:before{content:"\\F263"}.fa-odnoklassniki-square:before{content:"\\F264"}.fa-get-pocket:before{content:"\\F265"}.fa-wikipedia-w:before{content:"\\F266"}.fa-safari:before{content:"\\F267"}.fa-chrome:before{content:"\\F268"}.fa-firefox:before{content:"\\F269"}.fa-opera:before{content:"\\F26A"}.fa-internet-explorer:before{content:"\\F26B"}.fa-television:before,.fa-tv:before{content:"\\F26C"}.fa-contao:before{content:"\\F26D"}.fa-500px:before{content:"\\F26E"}.fa-amazon:before{content:"\\F270"}.fa-calendar-plus-o:before{content:"\\F271"}.fa-calendar-minus-o:before{content:"\\F272"}.fa-calendar-times-o:before{content:"\\F273"}.fa-calendar-check-o:before{content:"\\F274"}.fa-industry:before{content:"\\F275"}.fa-map-pin:before{content:"\\F276"}.fa-map-signs:before{content:"\\F277"}.fa-map-o:before{content:"\\F278"}.fa-map:before{content:"\\F279"}.fa-commenting:before{content:"\\F27A"}.fa-commenting-o:before{content:"\\F27B"}.fa-houzz:before{content:"\\F27C"}.fa-vimeo:before{content:"\\F27D"}.fa-black-tie:before{content:"\\F27E"}.fa-fonticons:before{content:"\\F280"}.fa-reddit-alien:before{content:"\\F281"}.fa-edge:before{content:"\\F282"}.fa-credit-card-alt:before{content:"\\F283"}.fa-codiepie:before{content:"\\F284"}.fa-modx:before{content:"\\F285"}.fa-fort-awesome:before{content:"\\F286"}.fa-usb:before{content:"\\F287"}.fa-product-hunt:before{content:"\\F288"}.fa-mixcloud:before{content:"\\F289"}.fa-scribd:before{content:"\\F28A"}.fa-pause-circle:before{content:"\\F28B"}.fa-pause-circle-o:before{content:"\\F28C"}.fa-stop-circle:before{content:"\\F28D"}.fa-stop-circle-o:before{content:"\\F28E"}.fa-shopping-bag:before{content:"\\F290"}.fa-shopping-basket:before{content:"\\F291"}.fa-hashtag:before{content:"\\F292"}.fa-bluetooth:before{content:"\\F293"}.fa-bluetooth-b:before{content:"\\F294"}.fa-percent:before{content:"\\F295"}.fa-gitlab:before{content:"\\F296"}.fa-wpbeginner:before{content:"\\F297"}.fa-wpforms:before{content:"\\F298"}.fa-envira:before{content:"\\F299"}.fa-universal-access:before{content:"\\F29A"}.fa-wheelchair-alt:before{content:"\\F29B"}.fa-question-circle-o:before{content:"\\F29C"}.fa-blind:before{content:"\\F29D"}.fa-audio-description:before{content:"\\F29E"}.fa-volume-control-phone:before{content:"\\F2A0"}.fa-braille:before{content:"\\F2A1"}.fa-assistive-listening-systems:before{content:"\\F2A2"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:"\\F2A3"}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:"\\F2A4"}.fa-glide:before{content:"\\F2A5"}.fa-glide-g:before{content:"\\F2A6"}.fa-sign-language:before,.fa-signing:before{content:"\\F2A7"}.fa-low-vision:before{content:"\\F2A8"}.fa-viadeo:before{content:"\\F2A9"}.fa-viadeo-square:before{content:"\\F2AA"}.fa-snapchat:before{content:"\\F2AB"}.fa-snapchat-ghost:before{content:"\\F2AC"}.fa-snapchat-square:before{content:"\\F2AD"}.fa-pied-piper:before{content:"\\F2AE"}.fa-first-order:before{content:"\\F2B0"}.fa-yoast:before{content:"\\F2B1"}.fa-themeisle:before{content:"\\F2B2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\\F2B3"}.fa-fa:before,.fa-font-awesome:before{content:"\\F2B4"}.fa-handshake-o:before{content:"\\F2B5"}.fa-envelope-open:before{content:"\\F2B6"}.fa-envelope-open-o:before{content:"\\F2B7"}.fa-linode:before{content:"\\F2B8"}.fa-address-book:before{content:"\\F2B9"}.fa-address-book-o:before{content:"\\F2BA"}.fa-address-card:before,.fa-vcard:before{content:"\\F2BB"}.fa-address-card-o:before,.fa-vcard-o:before{content:"\\F2BC"}.fa-user-circle:before{content:"\\F2BD"}.fa-user-circle-o:before{content:"\\F2BE"}.fa-user-o:before{content:"\\F2C0"}.fa-id-badge:before{content:"\\F2C1"}.fa-drivers-license:before,.fa-id-card:before{content:"\\F2C2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\\F2C3"}.fa-quora:before{content:"\\F2C4"}.fa-free-code-camp:before{content:"\\F2C5"}.fa-telegram:before{content:"\\F2C6"}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:"\\F2C7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\\F2C8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\\F2C9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\\F2CA"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\\F2CB"}.fa-shower:before{content:"\\F2CC"}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:"\\F2CD"}.fa-podcast:before{content:"\\F2CE"}.fa-window-maximize:before{content:"\\F2D0"}.fa-window-minimize:before{content:"\\F2D1"}.fa-window-restore:before{content:"\\F2D2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\\F2D3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\\F2D4"}.fa-bandcamp:before{content:"\\F2D5"}.fa-grav:before{content:"\\F2D6"}.fa-etsy:before{content:"\\F2D7"}.fa-imdb:before{content:"\\F2D8"}.fa-ravelry:before{content:"\\F2D9"}.fa-eercast:before{content:"\\F2DA"}.fa-microchip:before{content:"\\F2DB"}.fa-snowflake-o:before{content:"\\F2DC"}.fa-superpowers:before{content:"\\F2DD"}.fa-wpexplorer:before{content:"\\F2DE"}.fa-meetup:before{content:"\\F2E0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}',""]); -},function(A,M,t){M=A.exports=t(138)(),M.push([A.id,'*,:after,:before{box-sizing:border-box}body{font-family:Lato,sans-serif;font-size:15px;line-height:1.42857143;color:#8e8e8e;background-color:#edecec}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#46a5e0}a,a:focus,a:hover{text-decoration:none}a:focus,a:hover{color:#1f7fba}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#edecec;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:15px;text-align:left;background-color:#fff;border:1px solid transparent;border-radius:4px;box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:rgba(0,0,0,.08)}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#8e8e8e;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#333;background-color:rgba(0,0,0,.05)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#333;text-decoration:none;outline:0;background-color:rgba(0,0,0,.075)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#e4e4e4}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu>li>a{text-align:right}.navbar-right .dropdown-menu-left{left:0;right:auto}}.modal,.modal-open{overflow:hidden}.modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0);transform:translate(0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid transparent;border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:rgba(0,0,0,.1)}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:30px 35px 0;border-bottom:1px solid transparent}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:transparent}.modal-body{position:relative;padding:30px 35px}.modal-footer{padding:30px 35px;text-align:right;border-top:1px solid transparent}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:400px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Lato,sans-serif;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:13px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}@-ms-viewport{width:device-width}.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:active,:focus{outline:0}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body,html{min-height:100%}a{-webkit-transition:color;transition:color;-webkit-transition-duration:.3s;transition-duration:.3s}button{border:0}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translateY(-20px)}to{opacity:1;-webkit-transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translateY(20px)}to{opacity:1;-webkit-transform:translateY(0)}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1;-webkit-transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(20px)}}@keyframes fadeOutDown{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(20px)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutUp{0%{opacity:1;-webkit-transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(-20px)}}@keyframes fadeOutUp{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-20px)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.text-center{text-align:center!important}.text-left{text-align:left!important}.text-right{text-align:right!important}.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.row:after,.row:before{content:" ";display:table}.clearfix:after,.container-fluid:after,.container:after,.modal-footer:after,.modal-header:after,.row:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.p-relative{position:relative}.m-0{margin:0!important}.m-t-0{margin-top:0!important}.m-b-0{margin-bottom:0!important}.m-l-0{margin-left:0!important}.m-r-0{margin-right:0!important}.m-5{margin:5px!important}.m-t-5{margin-top:5px!important}.m-b-5{margin-bottom:5px!important}.m-l-5{margin-left:5px!important}.m-r-5{margin-right:5px!important}.m-10{margin:10px!important}.m-t-10{margin-top:10px!important}.m-b-10{margin-bottom:10px!important}.m-l-10{margin-left:10px!important}.m-r-10{margin-right:10px!important}.m-15{margin:15px!important}.m-t-15{margin-top:15px!important}.m-b-15{margin-bottom:15px!important}.m-l-15{margin-left:15px!important}.m-r-15{margin-right:15px!important}.m-20{margin:20px!important}.m-t-20{margin-top:20px!important}.m-b-20{margin-bottom:20px!important}.m-l-20{margin-left:20px!important}.m-r-20{margin-right:20px!important}.m-25{margin:25px!important}.m-t-25{margin-top:25px!important}.m-b-25{margin-bottom:25px!important}.m-l-25{margin-left:25px!important}.m-r-25{margin-right:25px!important}.m-30{margin:30px!important}.m-t-30{margin-top:30px!important}.m-b-30{margin-bottom:30px!important}.m-l-30{margin-left:30px!important}.m-r-30{margin-right:30px!important}.p-0{padding:0!important}.p-t-0{padding-top:0!important}.p-b-0{padding-bottom:0!important}.p-l-0{padding-left:0!important}.p-r-0{padding-right:0!important}.p-5{padding:5px!important}.p-t-5{padding-top:5px!important}.p-b-5{padding-bottom:5px!important}.p-l-5{padding-left:5px!important}.p-r-5{padding-right:5px!important}.p-10{padding:10px!important}.p-t-10{padding-top:10px!important}.p-b-10{padding-bottom:10px!important}.p-l-10{padding-left:10px!important}.p-r-10{padding-right:10px!important}.p-15{padding:15px!important}.p-t-15{padding-top:15px!important}.p-b-15{padding-bottom:15px!important}.p-l-15{padding-left:15px!important}.p-r-15{padding-right:15px!important}.p-20{padding:20px!important}.p-t-20{padding-top:20px!important}.p-b-20{padding-bottom:20px!important}.p-l-20{padding-left:20px!important}.p-r-20{padding-right:20px!important}.p-25{padding:25px!important}.p-t-25{padding-top:25px!important}.p-b-25{padding-bottom:25px!important}.p-l-25{padding-left:25px!important}.p-r-25{padding-right:25px!important}.p-30{padding:30px!important}.p-t-30{padding-top:30px!important}.p-b-30{padding-bottom:30px!important}.p-l-30{padding-left:30px!important}.p-r-30{padding-right:30px!important}@font-face{font-family:Lato;src:url('+t(514)+') format("woff2"),url('+t(513)+') format("woff");font-weight:400;font-style:normal}.form-control{border:0;border-bottom:1px solid #eee;color:#32393f;padding:5px;width:100%;font-size:13px;background-color:transparent}select.form-control{-webkit-appearance:none;-moz-appearance:none;border-radius:0;background:url('+t(517)+') no-repeat bottom 7px right}.input-group{position:relative}.input-group:not(:last-child){margin-bottom:25px}.input-group label:not(.ig-label){font-size:13px;display:block;margin-bottom:10px}.ig-label{position:absolute;text-align:center;bottom:7px;left:0;width:100%;-webkit-transition:all;transition:all;-webkit-transition-duration:.25s;transition-duration:.25s;padding:2px 0 3px;border-radius:2px;font-weight:400}.ig-helpers{z-index:1;width:100%;left:0}.ig-helpers,.ig-helpers:after,.ig-helpers:before{position:absolute;height:2px;bottom:0}.ig-helpers:after,.ig-helpers:before{content:"";width:0;-webkit-transition:all;transition:all;-webkit-transition-duration:.25s;transition-duration:.25s;background-color:#03a9f4}.ig-helpers:before{left:50%}.ig-helpers:after{right:50%}.ig-text{width:100%;height:40px;border:0;background:transparent;text-align:center;position:relative;z-index:1;border-bottom:1px solid #eee;color:#32393f;font-size:13px}.ig-text:focus+.ig-helpers:after,.ig-text:focus+.ig-helpers:before{width:50%}.ig-text:disabled~.ig-label,.ig-text:focus~.ig-label,.ig-text:valid~.ig-label{bottom:35px;font-size:13px;z-index:1}.ig-text:disabled{opacity:.5;filter:alpha(opacity=50)}.ig-dark .ig-text{color:#fff;border-color:hsla(0,0%,100%,.1)}.ig-dark .ig-helpers:after,.ig-dark .ig-helpers:before{background-color:#dfdfdf;height:1px}.ig-left .ig-label,.ig-left .ig-text{text-align:left}.ig-error .ig-label{color:#e23f3f}.ig-error .ig-helpers i:first-child,.ig-error .ig-helpers i:first-child:after,.ig-error .ig-helpers i:first-child:before{background:rgba(226,63,63,.43)}.ig-error .ig-helpers i:last-child,.ig-error .ig-helpers i:last-child:after,.ig-error .ig-helpers i:last-child:before{background:#e23f3f!important}.ig-error:after{content:"\\F05A";font-family:FontAwesome;position:absolute;top:17px;right:9px;font-size:20px;color:#d33d3e}.ig-search:before{font-family:fontAwesome;content:"\\F002";font-size:15px;position:absolute;left:2px;top:8px}.ig-search .ig-text{padding-left:25px}.set-expire{border:1px solid #eee;margin:35px 0 30px}.set-expire-item{padding:9px 5px 3px;position:relative;display:table-cell;width:1%;text-align:center}.set-expire-item:not(:last-child){border-right:1px solid #eee}.set-expire-title{font-size:10px;text-transform:uppercase}.set-expire-value{display:inline-block;overflow:hidden;position:relative;left:-8px}.set-expire-value input{font-size:20px;text-align:center;position:relative;right:-15px;border:0;color:#333;padding:0;height:25px;width:100%;font-weight:400}.set-expire-decrease,.set-expire-increase{position:absolute;width:20px;height:20px;background:url('+t(515)+') no-repeat 50%;background-size:85%;left:50%;margin-left:-10px;opacity:.2;filter:alpha(opacity=20);cursor:pointer}.set-expire-decrease:hover,.set-expire-increase:hover{opacity:.5;filter:alpha(opacity=50)}.set-expire-increase{top:-25px}.set-expire-decrease{bottom:-27px;-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.btn{border:0;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:2px;text-align:center;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}.btn:focus,.btn:hover{opacity:.9;filter:alpha(opacity=90)}.btn-block{display:block;width:100%}.btn-link{color:#545454;background-color:#eee}.btn-link:focus,.btn-link:hover{color:#545454;background-color:#dfdfdf}.btn-danger{color:#fff;background-color:#ff726f}.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#ff5450}.btn-primary{color:#fff;background-color:#50b2ff}.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#31a5ff}.btn-success{color:#fff;background-color:#33d46f}.btn-success:focus,.btn-success:hover{color:#fff;background-color:#28c061}.close{right:15px;font-weight:400;opacity:1;font-size:18px;position:absolute;text-align:center;top:16px;z-index:1;padding:0;border:0;background-color:transparent}.close span{width:25px;height:25px;display:block;border-radius:50%;line-height:24px;text-shadow:none}.close:not(.close-alt) span{background-color:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.8)}.close:not(.close-alt):focus span,.close:not(.close-alt):hover span{background-color:hsla(0,0%,100%,.2);color:#fff}.close-alt span{background-color:#efefef;color:#989898}.close-alt:focus span,.close-alt:hover span{background-color:#e8e8e8;color:#7b7b7b}.hidden{display:none!important}.copy-text input{width:100%;border-radius:1px;border:1px solid #eee;padding:7px 12px;font-size:13px;line-height:100%;cursor:text;-webkit-transition:border-color;transition:border-color;-webkit-transition-duration:.3s;transition-duration:.3s}.copy-text input:hover{border-color:#e1e1e1}.share-availability{margin-bottom:40px}.share-availability:after,.share-availability:before{position:absolute;bottom:-30px;font-size:10px}.share-availability:before{content:"01 Sec";left:0}.share-availability:after{content:"7 days";right:0}.login{height:100vh;min-height:500px;background:#32393f;text-align:center}.login:before{height:calc(100% - 110px);width:1px;content:""}.l-wrap,.login:before{display:inline-block;vertical-align:middle}.l-wrap{width:80%;max-width:500px;margin-top:-50px}.l-wrap.toggled{display:inline-block}.l-wrap .input-group:not(:last-child){margin-bottom:40px}.l-footer{height:110px;padding:0 50px}.lf-logo{float:right}.lf-logo img{width:40px}.lf-server{float:left;color:hsla(0,0%,100%,.4);font-size:20px;font-weight:400;padding-top:40px}@media (max-width:768px){.lf-logo,.lf-server{float:none;display:block;text-align:center;width:100%}.lf-logo{margin-bottom:5px}.lf-server{font-size:15px}}.lw-btn{width:50px;height:50px;border:1px solid #fff;display:inline-block;border-radius:50%;font-size:22px;color:#fff;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;opacity:.3;background-color:transparent;line-height:45px;padding:0}.lw-btn:hover{color:#fff;opacity:.8;border-color:#fff}.lw-btn i{display:block;width:100%;padding-left:3px}input:-webkit-autofill{-webkit-box-shadow:0 0 0 50px #32393f inset!important;-webkit-text-fill-color:#fff!important}.fe-header{padding:45px 55px 20px}@media (min-width:992px){.fe-header{position:relative}}@media (max-width:667px){.fe-header{padding:25px 25px 20px}}.fe-header h2{font-size:16px;font-weight:400;margin:0}.fe-header h2>span{margin-bottom:7px;display:inline-block}.fe-header h2>span:not(:first-child):before{content:"/";margin:0 4px;color:#8e8e8e}.fe-header p{margin-top:7px}.feh-usage{margin-top:12px;max-width:285px}@media (max-width:667px){.feh-usage{max-width:100%;font-size:12px}}.feh-usage>ul{margin-top:7px;list-style:none;padding:0}.feh-usage>ul>li{padding-right:0;display:inline-block}.fehu-chart{height:5px;background:#eee;position:relative;border-radius:2px;overflow:hidden}.fehu-chart>div{position:absolute;left:0;height:100%;background:#46a5e0}.feh-actions{list-style:none;padding:0;margin:0;position:absolute;right:35px;top:30px;z-index:11}@media (max-width:991px){.feh-actions{top:7px;right:10px;position:fixed}}.feh-actions>li{display:inline-block;text-align:right;vertical-align:top;line-height:100%}.feh-actions>li>.btn-group>button,.feh-actions>li>a{display:block;height:45px;min-width:45px;text-align:center;border-radius:50%;padding:0;border:0;background:none}@media (min-width:992px){.feh-actions>li>.btn-group>button,.feh-actions>li>a{color:#7b7b7b;font-size:21px;line-height:45px;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}.feh-actions>li>.btn-group>button:hover,.feh-actions>li>a:hover{background:rgba(0,0,0,.09)}}@media (max-width:991px){.feh-actions>li>.btn-group>button,.feh-actions>li>a{background:url('+t(237)+') no-repeat 50%}.feh-actions>li>.btn-group>button .fa-reorder,.feh-actions>li>a .fa-reorder{display:none}}@media (max-width:991px){.fe-header-mobile{background-color:#32393f;padding:10px 50px 9px 12px;text-align:center;position:fixed;z-index:10;box-shadow:0 0 10px rgba(0,0,0,.3);left:0;top:0;width:100%}.fe-header-mobile .mh-logo{height:35px;position:relative;top:4px}.feh-trigger{width:41px;height:41px;cursor:pointer;float:left;position:relative;text-align:center}.feh-trigger:after,.feh-trigger:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.feh-trigger:after{z-index:1}.feh-trigger:before{background:hsla(0,0%,100%,.1);-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transform:scale(0);transform:scale(0)}.feht-toggled:before{-webkit-transform:scale(1);transform:scale(1)}.feht-toggled .feht-lines{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.feht-toggled .feht-lines>div.top{width:12px;transform:translateX(8px) translateY(1px) rotate(45deg);-webkit-transform:translateX(8px) translateY(1px) rotate(45deg)}.feht-toggled .feht-lines>div.bottom{width:12px;transform:translateX(8px) translateY(-1px) rotate(-45deg);-webkit-transform:translateX(8px) translateY(-1px) rotate(-45deg)}.feht-lines,.feht-lines>div{-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}.feht-lines{width:18px;height:12px;display:inline-block;margin-top:14px}.feht-lines>div{background-color:#eaeaea;width:18px;height:2px}.feht-lines>div.center{margin:3px 0}}.fe-sidebar{width:300px;background-color:#32393f;position:fixed;height:100%;overflow:hidden;padding:35px}@media (min-width:992px){.fe-sidebar{-webkit-transform:translateZ(0);transform:translateZ(0)}}@media (max-width:991px){.fe-sidebar{padding-top:85px;z-index:9;box-shadow:0 0 10px rgba(0,0,0,.65);-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transform:translate3d(-315px,0,0);transform:translate3d(-315px,0,0)}.fe-sidebar.toggled{-webkit-transform:translateZ(0);transform:translateZ(0)}}.fe-sidebar a{color:hsla(0,0%,100%,.58)}.fe-sidebar a:hover{color:#fff}.fes-header{margin-bottom:40px}.fes-header h2,.fes-header img{float:left}.fes-header h2{margin:13px 0 0 10px;font-weight:400}.fes-header img{width:32px}.fesl-inner{height:calc(100vh - 260px);overflow:auto;padding:0;margin:0 -35px}.fesl-inner li{position:relative}.fesl-inner li>a{display:block;padding:10px 40px 12px 65px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fesl-inner li>a:before{font-family:FontAwesome;content:"\\F0A0";font-size:17px;position:absolute;top:10px;left:35px;opacity:.8;filter:alpha(opacity=80)}.fesl-inner li>a.fesli-loading:before{content:"";width:20px;height:20px;border-radius:50%;-webkit-animation-name:zoomIn;animation-name:zoomIn;-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-fill-mode:both;animation-fill-mode:both;border:2px solid hsla(0,0%,100%,.1);border-bottom-color:hsla(0,0%,100%,.5);position:absolute;z-index:1;-webkit-animation:zoomIn .25s,spin .7s .25s infinite linear;animation:zoomIn .25s,spin .7s .25s infinite linear;left:32px;top:0;bottom:0;margin:auto}.fesl-inner li.active{background-color:rgba(0,0,0,.2)}.fesl-inner li.active>a{color:#fff}.fesl-inner li:not(.active):hover{background-color:rgba(0,0,0,.1)}.fesl-inner li:not(.active):hover>a{color:#fff}.fesl-inner li:hover .fesli-trigger{opacity:.6;filter:alpha(opacity=60)}.fesl-inner li:hover .fesli-trigger:hover{opacity:1;filter:alpha(opacity=100)}.fesl-inner ul{list-style:none;padding:0;margin:0}.fesl-inner:hover .scrollbar-vertical{opacity:1}.fesli-trigger{filter:alpha(opacity=0);-webkit-transition:all;transition:all;-webkit-transition-duration:.2s;transition-duration:.2s;top:0;right:0;width:40px;cursor:pointer;background:url('+t(237)+') no-repeat 0}.fesli-trigger,.scrollbar-vertical{opacity:0;position:absolute;height:100%}.scrollbar-vertical{right:5px;width:4px;-webkit-transition:opacity;transition:opacity;-webkit-transition-duration:.3s;transition-duration:.3s}.scrollbar-vertical div{border-radius:1px!important;background-color:#6a6a6a!important}.fes-host{position:fixed;left:0;bottom:0;z-index:1;background:#32393f;color:hsla(0,0%,100%,.4);font-size:15px;font-weight:400;width:300px;padding:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fes-host>i{margin-right:10px}.fesl-row{padding-right:40px;padding-top:5px;padding-bottom:5px;position:relative}@media (min-width:668px){.fesl-row{display:flex;flex-flow:row nowrap;justify-content:space-between}}.fesl-row:after,.fesl-row:before{content:" ";display:table}.fesl-row:after{clear:both}@media (min-width:668px){header.fesl-row{margin-bottom:20px;border-bottom:1px solid #f0f0f0;padding-left:40px}header.fesl-row .fesl-item,header.fesl-row .fesli-sort{-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}header.fesl-row .fesl-item{cursor:pointer;color:#8e8e8e;font-weight:500;margin-bottom:-5px}header.fesl-row .fesl-item>.fesli-sort{float:right;margin:4px 0 0;opacity:0;filter:alpha(opacity=0);color:#32393f;font-size:14px}header.fesl-row .fesl-item:hover:not(.fi-actions){background:#f5f5f5;color:#32393f}header.fesl-row .fesl-item:hover:not(.fi-actions)>.fesli-sort{opacity:.5;filter:alpha(opacity=50)}}@media (max-width:667px){header.fesl-row{display:none}}div.fesl-row{padding-left:85px;border-bottom:1px solid transparent;cursor:default}@media (max-width:667px){div.fesl-row{padding-left:70px;padding-right:45px}}div.fesl-row:nth-child(2n){background-color:#fafafa}div.fesl-row:hover{background-color:#fbf7dc}div.fesl-row[data-type]:before{font-family:fontAwesome;width:35px;height:35px;text-align:center;line-height:35px;position:absolute;border-radius:50%;font-size:16px;left:50px;top:9px;color:#fff}@media (max-width:667px){div.fesl-row[data-type]:before{left:20px}}@media (max-width:667px){div.fesl-row[data-type=folder] .fesl-item.fi-name{padding-top:10px;padding-bottom:7px}div.fesl-row[data-type=folder] .fesl-item.fi-modified,div.fesl-row[data-type=folder] .fesl-item.fi-size{display:none}}div.fesl-row[data-type=folder]:before{content:"\\F114";background-color:#a1d6dd}div.fesl-row[data-type=pdf]:before{content:"\\F1C1";background-color:#fa7775}div.fesl-row[data-type=zip]:before{content:"\\F1C6";background-color:#427089}div.fesl-row[data-type=audio]:before{content:"\\F1C7";background-color:#009688}div.fesl-row[data-type=code]:before{content:"\\F1C9";background-color:#997867}div.fesl-row[data-type=excel]:before{content:"\\F1C3";background-color:#64c866}div.fesl-row[data-type=image]:before{content:"\\F1C5";background-color:#f06292}div.fesl-row[data-type=video]:before{content:"\\F1C8";background-color:#f8c363}div.fesl-row[data-type=other]:before{content:"\\F016";background-color:#afafaf}div.fesl-row[data-type=text]:before{content:"\\F0F6";background-color:#8a8a8a}div.fesl-row[data-type=doc]:before{content:"\\F1C2";background-color:#2196f5}div.fesl-row[data-type=presentation]:before{content:"\\F1C4";background-color:#896ea6}div.fesl-row.fesl-loading:before{content:""}div.fesl-row.fesl-loading:after{content:"";width:20px;height:20px;border-radius:50%;-webkit-animation-name:zoomIn;animation-name:zoomIn;-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-fill-mode:both;animation-fill-mode:both;border:2px solid hsla(0,0%,100%,.5);border-bottom-color:#fff;position:absolute;z-index:1;-webkit-animation:zoomIn .25s,spin .7s .25s infinite linear;animation:zoomIn .25s,spin .7s .25s infinite linear;left:57px;top:17px}@media (max-width:667px){div.fesl-row.fesl-loading:after{left:27px}}.fesl-item{display:block}.fesl-item a{color:#818181}@media (min-width:668px){.fesl-item:not(.fi-actions){text-overflow:ellipsis;padding:10px 15px;white-space:nowrap;overflow:hidden}.fesl-item.fi-name{flex:3}.fesl-item.fi-size{width:140px}.fesl-item.fi-modified{width:190px}.fesl-item.fi-actions{width:40px}}@media (max-width:667px){.fesl-item{padding:0}.fesl-item.fi-name{width:100%;margin-bottom:3px}.fesl-item.fi-modified,.fesl-item.fi-size{font-size:12px;color:#b5b5b5;float:left}.fesl-item.fi-modified{max-width:72px;white-space:nowrap;overflow:hidden}.fesl-item.fi-size{margin-right:10px}.fesl-item.fi-actions{position:absolute;top:5px;right:10px}}.fia-toggle{height:36px;width:36px;background:transparent url('+t(516)+') no-repeat 50%;position:relative;top:3px;opacity:.4;filter:alpha(opacity=40)}.fia-toggle:hover{opacity:.7;filter:alpha(opacity=70)}.fi-actions .dropdown-menu{background-color:transparent;box-shadow:none;padding:0;right:38px;left:auto;margin:0;height:100%;text-align:right}.fi-actions .dropdown.open .dropdown-menu .fiad-action{right:0}.fiad-action{height:35px;width:35px;background:#ffc107;display:inline-block;border-radius:50%;text-align:center;line-height:35px;font-weight:400;position:relative;top:4px;margin-left:5px;-webkit-animation-name:fiad-action-anim;animation-name:fiad-action-anim;-webkit-transform-origin:center center;transform-origin:center center;-webkit-backface-visibility:none;backface-visibility:none;box-shadow:0 2px 4px rgba(0,0,0,.1)}.fiad-action:nth-child(2){-webkit-animation-duration:.1s;animation-duration:.1s}.fiad-action:first-child{-webkit-animation-duration:.25s;animation-duration:.25s}.fiad-action>i{font-size:14px;color:#fff}.fiad-action:hover{background-color:#f7b900}@-webkit-keyframes fiad-action-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0);right:-20px}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100);right:0}}@keyframes fiad-action-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0);right:-20px}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100);right:0}}.file-explorer{background-color:#fff;position:relative;height:100%}.file-explorer.toggled{height:100vh;overflow:hidden}.fe-body{min-height:100vh;overflow:auto}@media (min-width:992px){.fe-body{padding:0 0 40px 300px}}@media (max-width:991px){.fe-body{padding:75px 0 80px}}.feb-actions{position:fixed;bottom:30px;right:30px}.feb-actions .dropdown-menu{min-width:55px;width:55px;text-align:center;background:transparent;box-shadow:none;margin:0}.feb-actions.open .feba-btn{-webkit-transform:scale(1);transform:scale(1)}.feb-actions.open .feba-btn:first-child{-webkit-animation-name:feba-btn-anim;animation-name:feba-btn-anim;-webkit-animation-duration:.3s;animation-duration:.3s}.feb-actions.open .feba-btn:last-child{-webkit-animation-name:feba-btn-anim;animation-name:feba-btn-anim;-webkit-animation-duration:.1s;animation-duration:.1s}.feb-actions.open .feba-toggle{background:#ff403c}.feb-actions.open .feba-toggle>span{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.feba-toggle{width:55px;height:55px;line-height:55px;border-radius:50%;background:#ff726f;box-shadow:0 2px 3px rgba(0,0,0,.15);display:inline-block;text-align:center;border:0;padding:0}.feba-toggle span{display:inline-block;height:100%;width:100%}.feba-toggle i{color:#fff;font-size:17px;line-height:58px}.feba-toggle,.feba-toggle>span{-webkit-transition:all;transition:all;-webkit-transition-duration:.25s;transition-duration:.25s;-webkit-backface-visibility:hidden;backface-visibility:hidden}.feba-btn{width:40px;margin-top:10px;height:40px;border-radius:50%;text-align:center;display:inline-block;line-height:40px;box-shadow:0 2px 3px rgba(0,0,0,.15);-webkit-transform:scale(0);transform:scale(0);position:relative}.feba-btn,.feba-btn:focus,.feba-btn:hover{color:#fff}.feba-btn label{width:100%;height:100%;position:absolute;left:0;top:0;cursor:pointer}.feba-bucket{background:#ffc155}.feba-upload{background:#ffc107}@-webkit-keyframes feba-btn-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0)}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100)}}@keyframes feba-btn-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0)}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100)}}.ie-warning{background-color:#ff5252;width:100%;height:100%;position:fixed;left:0;top:0;text-align:center}.ie-warning:before{width:1px;content:"";height:100%}.ie-warning .iw-inner,.ie-warning:before{display:inline-block;vertical-align:middle}.iw-inner{width:470px;height:300px;background-color:#fff;border-radius:5px;padding:40px;position:relative}.iw-inner ul{list-style:none;padding:0;margin:0;width:230px;margin-left:80px;margin-top:16px}.iw-inner ul>li{float:left}.iw-inner ul>li>a{display:block;padding:10px 15px 7px;font-size:14px;margin:0 1px;border-radius:3px}.iw-inner ul>li>a:hover{background:#eee}.iw-inner ul>li>a img{height:40px;margin-bottom:5px}.iwi-icon{color:#ff5252;font-size:40px;display:block;line-height:100%;margin-bottom:15px}.iwi-skip{position:absolute;left:0;bottom:-35px;width:100%;color:hsla(0,0%,100%,.6);cursor:pointer}.iwi-skip:hover{color:#fff}.dropdown-menu{padding:15px 0;top:0;margin-top:-1px}.dropdown-menu>li>a{padding:8px 20px;font-size:15px}.dropdown-menu>li>a>i{width:20px;position:relative;top:1px}.dropdown-menu-right>li>a{text-align:right}.alert{border:0;position:fixed;max-width:500px;margin:0;box-shadow:0 4px 5px rgba(0,0,0,.1);color:#fff;width:100%;right:20px;border-radius:3px;padding:17px 50px 17px 17px;z-index:10010;-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.alert:not(.progress){top:20px}@media (min-width:768px){.alert:not(.progress){left:50%;margin-left:-250px}}.alert.progress{bottom:20px;right:20px}.alert.alert-danger{background:#ff726f}.alert.alert-success{background:#33d46f}.alert.alert-info{background:#50b2ff}@media (max-width:767px){.alert{left:20px;width:calc(100% - 40px);max-width:100%}}.alert .progress{margin:10px 10px 8px 0;height:5px;box-shadow:none;border-radius:1px;background-color:#50b2ff;border-radius:2px;overflow:hidden}.alert .progress-bar{box-shadow:none;background-color:#fff;height:100%}.alert .close{position:absolute;top:15px}@media (min-width:768px){.modal{text-align:center}.modal:before{content:"";height:100%;width:1px}.modal .modal-dialog,.modal:before{display:inline-block;vertical-align:middle}.modal .modal-dialog{text-align:left;margin:10px auto}}.modal-dark .modal-header{color:hsla(0,0%,100%,.4)}.modal-dark .modal-header small{color:hsla(0,0%,100%,.2)}.modal-dark .modal-content{background-color:#32393f}.modal-backdrop{-webkit-animation-name:fadeIn;animation-name:fadeIn;-webkit-animation-fill-mode:both;animation-fill-mode:both}.modal-backdrop,.modal-dialog{-webkit-animation-duration:.2s;animation-duration:.2s}.modal-dialog{-webkit-animation-name:zoomIn;animation-name:zoomIn;-webkit-animation-fill-mode:both;animation-fill-mode:both}.modal-header{color:#333;position:relative}.modal-header small{display:block;text-transform:none;font-size:12px;margin-top:5px;color:#a8a8a8}.modal-content{border-radius:3px;box-shadow:none}.modal-footer{padding:0 30px 30px}.modal-confirm .modal-dialog,.modal-footer{text-align:center}.mc-icon{margin:0 0 10px}.mc-icon>i{font-size:60px}.mci-red{color:#ff8f8f}.mci-amber{color:#ffc107}.mci-green{color:#64e096}.mc-text{color:#333}.mc-sub{color:#bdbdbd;margin-top:5px;font-size:13px}@media (max-width:767px){.modal-about{text-align:center}.modal-about .modal-dialog{max-width:400px;width:90%;margin:20px auto 0}}.ma-inner{display:flex;flex-direction:row;align-items:center;min-height:350px;position:relative}@media (min-width:768px){.ma-inner:before{content:"";width:150px;height:100%;top:0;left:0;position:absolute;border-radius:3px 0 0 3px;background-color:#23282c}}.mai-item:first-child{width:150px;text-align:center}.mai-item:last-child{flex:4;padding:30px}.maii-logo{width:70px;position:relative}.maii-list{list-style:none;padding:0}.maii-list>li{margin-bottom:15px}.maii-list>li div{color:hsla(0,0%,100%,.8);text-transform:uppercase;font-size:14px}.maii-list>li small{font-size:13px;color:hsla(0,0%,100%,.4)}.toggle-password{position:absolute;bottom:30px;right:35px;width:30px;height:30px;border:1px solid #eee;border-radius:0;text-align:center;cursor:pointer;z-index:10;background-color:#fff;padding-top:5px}.toggle-password.toggled{background:#eee}.pm-body{padding-bottom:30px}.pmb-header{margin-bottom:35px}.pmb-list{display:flex;flex-flow:row nowrap;align-items:center;justify-content:center;padding:10px 35px}.pmb-list:nth-child(2n){background-color:#f7f7f7}.pmb-list .form-control{padding-left:0;padding-right:0}header.pmb-list{margin:20px 0 10px}.pmbl-item{display:block;font-size:13px}.pmbl-item:first-child{flex:2}.pmbl-item:nth-child(2){margin:0 25px;width:150px}.pmbl-item:nth-child(3){width:70px}div.pmb-list select{border:0}div.pmb-list .pml-item:not(:last-child){padding:0 5px}.modal-create-bucket .modal-dialog{position:fixed;right:25px;bottom:95px;margin:0;height:110px}.modal-create-bucket .modal-content{width:100%;height:100%}',""]); +"use strict";function t(A,M){if("string"!=typeof A)throw new TypeError("argument str must be a string");for(var t={},I=M||{},i=A.split(T),E=I.decode||e,N=0;Nli{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\\F000"}.fa-music:before{content:"\\F001"}.fa-search:before{content:"\\F002"}.fa-envelope-o:before{content:"\\F003"}.fa-heart:before{content:"\\F004"}.fa-star:before{content:"\\F005"}.fa-star-o:before{content:"\\F006"}.fa-user:before{content:"\\F007"}.fa-film:before{content:"\\F008"}.fa-th-large:before{content:"\\F009"}.fa-th:before{content:"\\F00A"}.fa-th-list:before{content:"\\F00B"}.fa-check:before{content:"\\F00C"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\\F00D"}.fa-search-plus:before{content:"\\F00E"}.fa-search-minus:before{content:"\\F010"}.fa-power-off:before{content:"\\F011"}.fa-signal:before{content:"\\F012"}.fa-cog:before,.fa-gear:before{content:"\\F013"}.fa-trash-o:before{content:"\\F014"}.fa-home:before{content:"\\F015"}.fa-file-o:before{content:"\\F016"}.fa-clock-o:before{content:"\\F017"}.fa-road:before{content:"\\F018"}.fa-download:before{content:"\\F019"}.fa-arrow-circle-o-down:before{content:"\\F01A"}.fa-arrow-circle-o-up:before{content:"\\F01B"}.fa-inbox:before{content:"\\F01C"}.fa-play-circle-o:before{content:"\\F01D"}.fa-repeat:before,.fa-rotate-right:before{content:"\\F01E"}.fa-refresh:before{content:"\\F021"}.fa-list-alt:before{content:"\\F022"}.fa-lock:before{content:"\\F023"}.fa-flag:before{content:"\\F024"}.fa-headphones:before{content:"\\F025"}.fa-volume-off:before{content:"\\F026"}.fa-volume-down:before{content:"\\F027"}.fa-volume-up:before{content:"\\F028"}.fa-qrcode:before{content:"\\F029"}.fa-barcode:before{content:"\\F02A"}.fa-tag:before{content:"\\F02B"}.fa-tags:before{content:"\\F02C"}.fa-book:before{content:"\\F02D"}.fa-bookmark:before{content:"\\F02E"}.fa-print:before{content:"\\F02F"}.fa-camera:before{content:"\\F030"}.fa-font:before{content:"\\F031"}.fa-bold:before{content:"\\F032"}.fa-italic:before{content:"\\F033"}.fa-text-height:before{content:"\\F034"}.fa-text-width:before{content:"\\F035"}.fa-align-left:before{content:"\\F036"}.fa-align-center:before{content:"\\F037"}.fa-align-right:before{content:"\\F038"}.fa-align-justify:before{content:"\\F039"}.fa-list:before{content:"\\F03A"}.fa-dedent:before,.fa-outdent:before{content:"\\F03B"}.fa-indent:before{content:"\\F03C"}.fa-video-camera:before{content:"\\F03D"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\\F03E"}.fa-pencil:before{content:"\\F040"}.fa-map-marker:before{content:"\\F041"}.fa-adjust:before{content:"\\F042"}.fa-tint:before{content:"\\F043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\\F044"}.fa-share-square-o:before{content:"\\F045"}.fa-check-square-o:before{content:"\\F046"}.fa-arrows:before{content:"\\F047"}.fa-step-backward:before{content:"\\F048"}.fa-fast-backward:before{content:"\\F049"}.fa-backward:before{content:"\\F04A"}.fa-play:before{content:"\\F04B"}.fa-pause:before{content:"\\F04C"}.fa-stop:before{content:"\\F04D"}.fa-forward:before{content:"\\F04E"}.fa-fast-forward:before{content:"\\F050"}.fa-step-forward:before{content:"\\F051"}.fa-eject:before{content:"\\F052"}.fa-chevron-left:before{content:"\\F053"}.fa-chevron-right:before{content:"\\F054"}.fa-plus-circle:before{content:"\\F055"}.fa-minus-circle:before{content:"\\F056"}.fa-times-circle:before{content:"\\F057"}.fa-check-circle:before{content:"\\F058"}.fa-question-circle:before{content:"\\F059"}.fa-info-circle:before{content:"\\F05A"}.fa-crosshairs:before{content:"\\F05B"}.fa-times-circle-o:before{content:"\\F05C"}.fa-check-circle-o:before{content:"\\F05D"}.fa-ban:before{content:"\\F05E"}.fa-arrow-left:before{content:"\\F060"}.fa-arrow-right:before{content:"\\F061"}.fa-arrow-up:before{content:"\\F062"}.fa-arrow-down:before{content:"\\F063"}.fa-mail-forward:before,.fa-share:before{content:"\\F064"}.fa-expand:before{content:"\\F065"}.fa-compress:before{content:"\\F066"}.fa-plus:before{content:"\\F067"}.fa-minus:before{content:"\\F068"}.fa-asterisk:before{content:"\\F069"}.fa-exclamation-circle:before{content:"\\F06A"}.fa-gift:before{content:"\\F06B"}.fa-leaf:before{content:"\\F06C"}.fa-fire:before{content:"\\F06D"}.fa-eye:before{content:"\\F06E"}.fa-eye-slash:before{content:"\\F070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\\F071"}.fa-plane:before{content:"\\F072"}.fa-calendar:before{content:"\\F073"}.fa-random:before{content:"\\F074"}.fa-comment:before{content:"\\F075"}.fa-magnet:before{content:"\\F076"}.fa-chevron-up:before{content:"\\F077"}.fa-chevron-down:before{content:"\\F078"}.fa-retweet:before{content:"\\F079"}.fa-shopping-cart:before{content:"\\F07A"}.fa-folder:before{content:"\\F07B"}.fa-folder-open:before{content:"\\F07C"}.fa-arrows-v:before{content:"\\F07D"}.fa-arrows-h:before{content:"\\F07E"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\\F080"}.fa-twitter-square:before{content:"\\F081"}.fa-facebook-square:before{content:"\\F082"}.fa-camera-retro:before{content:"\\F083"}.fa-key:before{content:"\\F084"}.fa-cogs:before,.fa-gears:before{content:"\\F085"}.fa-comments:before{content:"\\F086"}.fa-thumbs-o-up:before{content:"\\F087"}.fa-thumbs-o-down:before{content:"\\F088"}.fa-star-half:before{content:"\\F089"}.fa-heart-o:before{content:"\\F08A"}.fa-sign-out:before{content:"\\F08B"}.fa-linkedin-square:before{content:"\\F08C"}.fa-thumb-tack:before{content:"\\F08D"}.fa-external-link:before{content:"\\F08E"}.fa-sign-in:before{content:"\\F090"}.fa-trophy:before{content:"\\F091"}.fa-github-square:before{content:"\\F092"}.fa-upload:before{content:"\\F093"}.fa-lemon-o:before{content:"\\F094"}.fa-phone:before{content:"\\F095"}.fa-square-o:before{content:"\\F096"}.fa-bookmark-o:before{content:"\\F097"}.fa-phone-square:before{content:"\\F098"}.fa-twitter:before{content:"\\F099"}.fa-facebook-f:before,.fa-facebook:before{content:"\\F09A"}.fa-github:before{content:"\\F09B"}.fa-unlock:before{content:"\\F09C"}.fa-credit-card:before{content:"\\F09D"}.fa-feed:before,.fa-rss:before{content:"\\F09E"}.fa-hdd-o:before{content:"\\F0A0"}.fa-bullhorn:before{content:"\\F0A1"}.fa-bell:before{content:"\\F0F3"}.fa-certificate:before{content:"\\F0A3"}.fa-hand-o-right:before{content:"\\F0A4"}.fa-hand-o-left:before{content:"\\F0A5"}.fa-hand-o-up:before{content:"\\F0A6"}.fa-hand-o-down:before{content:"\\F0A7"}.fa-arrow-circle-left:before{content:"\\F0A8"}.fa-arrow-circle-right:before{content:"\\F0A9"}.fa-arrow-circle-up:before{content:"\\F0AA"}.fa-arrow-circle-down:before{content:"\\F0AB"}.fa-globe:before{content:"\\F0AC"}.fa-wrench:before{content:"\\F0AD"}.fa-tasks:before{content:"\\F0AE"}.fa-filter:before{content:"\\F0B0"}.fa-briefcase:before{content:"\\F0B1"}.fa-arrows-alt:before{content:"\\F0B2"}.fa-group:before,.fa-users:before{content:"\\F0C0"}.fa-chain:before,.fa-link:before{content:"\\F0C1"}.fa-cloud:before{content:"\\F0C2"}.fa-flask:before{content:"\\F0C3"}.fa-cut:before,.fa-scissors:before{content:"\\F0C4"}.fa-copy:before,.fa-files-o:before{content:"\\F0C5"}.fa-paperclip:before{content:"\\F0C6"}.fa-floppy-o:before,.fa-save:before{content:"\\F0C7"}.fa-square:before{content:"\\F0C8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\\F0C9"}.fa-list-ul:before{content:"\\F0CA"}.fa-list-ol:before{content:"\\F0CB"}.fa-strikethrough:before{content:"\\F0CC"}.fa-underline:before{content:"\\F0CD"}.fa-table:before{content:"\\F0CE"}.fa-magic:before{content:"\\F0D0"}.fa-truck:before{content:"\\F0D1"}.fa-pinterest:before{content:"\\F0D2"}.fa-pinterest-square:before{content:"\\F0D3"}.fa-google-plus-square:before{content:"\\F0D4"}.fa-google-plus:before{content:"\\F0D5"}.fa-money:before{content:"\\F0D6"}.fa-caret-down:before{content:"\\F0D7"}.fa-caret-up:before{content:"\\F0D8"}.fa-caret-left:before{content:"\\F0D9"}.fa-caret-right:before{content:"\\F0DA"}.fa-columns:before{content:"\\F0DB"}.fa-sort:before,.fa-unsorted:before{content:"\\F0DC"}.fa-sort-desc:before,.fa-sort-down:before{content:"\\F0DD"}.fa-sort-asc:before,.fa-sort-up:before{content:"\\F0DE"}.fa-envelope:before{content:"\\F0E0"}.fa-linkedin:before{content:"\\F0E1"}.fa-rotate-left:before,.fa-undo:before{content:"\\F0E2"}.fa-gavel:before,.fa-legal:before{content:"\\F0E3"}.fa-dashboard:before,.fa-tachometer:before{content:"\\F0E4"}.fa-comment-o:before{content:"\\F0E5"}.fa-comments-o:before{content:"\\F0E6"}.fa-bolt:before,.fa-flash:before{content:"\\F0E7"}.fa-sitemap:before{content:"\\F0E8"}.fa-umbrella:before{content:"\\F0E9"}.fa-clipboard:before,.fa-paste:before{content:"\\F0EA"}.fa-lightbulb-o:before{content:"\\F0EB"}.fa-exchange:before{content:"\\F0EC"}.fa-cloud-download:before{content:"\\F0ED"}.fa-cloud-upload:before{content:"\\F0EE"}.fa-user-md:before{content:"\\F0F0"}.fa-stethoscope:before{content:"\\F0F1"}.fa-suitcase:before{content:"\\F0F2"}.fa-bell-o:before{content:"\\F0A2"}.fa-coffee:before{content:"\\F0F4"}.fa-cutlery:before{content:"\\F0F5"}.fa-file-text-o:before{content:"\\F0F6"}.fa-building-o:before{content:"\\F0F7"}.fa-hospital-o:before{content:"\\F0F8"}.fa-ambulance:before{content:"\\F0F9"}.fa-medkit:before{content:"\\F0FA"}.fa-fighter-jet:before{content:"\\F0FB"}.fa-beer:before{content:"\\F0FC"}.fa-h-square:before{content:"\\F0FD"}.fa-plus-square:before{content:"\\F0FE"}.fa-angle-double-left:before{content:"\\F100"}.fa-angle-double-right:before{content:"\\F101"}.fa-angle-double-up:before{content:"\\F102"}.fa-angle-double-down:before{content:"\\F103"}.fa-angle-left:before{content:"\\F104"}.fa-angle-right:before{content:"\\F105"}.fa-angle-up:before{content:"\\F106"}.fa-angle-down:before{content:"\\F107"}.fa-desktop:before{content:"\\F108"}.fa-laptop:before{content:"\\F109"}.fa-tablet:before{content:"\\F10A"}.fa-mobile-phone:before,.fa-mobile:before{content:"\\F10B"}.fa-circle-o:before{content:"\\F10C"}.fa-quote-left:before{content:"\\F10D"}.fa-quote-right:before{content:"\\F10E"}.fa-spinner:before{content:"\\F110"}.fa-circle:before{content:"\\F111"}.fa-mail-reply:before,.fa-reply:before{content:"\\F112"}.fa-github-alt:before{content:"\\F113"}.fa-folder-o:before{content:"\\F114"}.fa-folder-open-o:before{content:"\\F115"}.fa-smile-o:before{content:"\\F118"}.fa-frown-o:before{content:"\\F119"}.fa-meh-o:before{content:"\\F11A"}.fa-gamepad:before{content:"\\F11B"}.fa-keyboard-o:before{content:"\\F11C"}.fa-flag-o:before{content:"\\F11D"}.fa-flag-checkered:before{content:"\\F11E"}.fa-terminal:before{content:"\\F120"}.fa-code:before{content:"\\F121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\\F122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\\F123"}.fa-location-arrow:before{content:"\\F124"}.fa-crop:before{content:"\\F125"}.fa-code-fork:before{content:"\\F126"}.fa-chain-broken:before,.fa-unlink:before{content:"\\F127"}.fa-question:before{content:"\\F128"}.fa-info:before{content:"\\F129"}.fa-exclamation:before{content:"\\F12A"}.fa-superscript:before{content:"\\F12B"}.fa-subscript:before{content:"\\F12C"}.fa-eraser:before{content:"\\F12D"}.fa-puzzle-piece:before{content:"\\F12E"}.fa-microphone:before{content:"\\F130"}.fa-microphone-slash:before{content:"\\F131"}.fa-shield:before{content:"\\F132"}.fa-calendar-o:before{content:"\\F133"}.fa-fire-extinguisher:before{content:"\\F134"}.fa-rocket:before{content:"\\F135"}.fa-maxcdn:before{content:"\\F136"}.fa-chevron-circle-left:before{content:"\\F137"}.fa-chevron-circle-right:before{content:"\\F138"}.fa-chevron-circle-up:before{content:"\\F139"}.fa-chevron-circle-down:before{content:"\\F13A"}.fa-html5:before{content:"\\F13B"}.fa-css3:before{content:"\\F13C"}.fa-anchor:before{content:"\\F13D"}.fa-unlock-alt:before{content:"\\F13E"}.fa-bullseye:before{content:"\\F140"}.fa-ellipsis-h:before{content:"\\F141"}.fa-ellipsis-v:before{content:"\\F142"}.fa-rss-square:before{content:"\\F143"}.fa-play-circle:before{content:"\\F144"}.fa-ticket:before{content:"\\F145"}.fa-minus-square:before{content:"\\F146"}.fa-minus-square-o:before{content:"\\F147"}.fa-level-up:before{content:"\\F148"}.fa-level-down:before{content:"\\F149"}.fa-check-square:before{content:"\\F14A"}.fa-pencil-square:before{content:"\\F14B"}.fa-external-link-square:before{content:"\\F14C"}.fa-share-square:before{content:"\\F14D"}.fa-compass:before{content:"\\F14E"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\\F150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\\F151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\\F152"}.fa-eur:before,.fa-euro:before{content:"\\F153"}.fa-gbp:before{content:"\\F154"}.fa-dollar:before,.fa-usd:before{content:"\\F155"}.fa-inr:before,.fa-rupee:before{content:"\\F156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\\F157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\\F158"}.fa-krw:before,.fa-won:before{content:"\\F159"}.fa-bitcoin:before,.fa-btc:before{content:"\\F15A"}.fa-file:before{content:"\\F15B"}.fa-file-text:before{content:"\\F15C"}.fa-sort-alpha-asc:before{content:"\\F15D"}.fa-sort-alpha-desc:before{content:"\\F15E"}.fa-sort-amount-asc:before{content:"\\F160"}.fa-sort-amount-desc:before{content:"\\F161"}.fa-sort-numeric-asc:before{content:"\\F162"}.fa-sort-numeric-desc:before{content:"\\F163"}.fa-thumbs-up:before{content:"\\F164"}.fa-thumbs-down:before{content:"\\F165"}.fa-youtube-square:before{content:"\\F166"}.fa-youtube:before{content:"\\F167"}.fa-xing:before{content:"\\F168"}.fa-xing-square:before{content:"\\F169"}.fa-youtube-play:before{content:"\\F16A"}.fa-dropbox:before{content:"\\F16B"}.fa-stack-overflow:before{content:"\\F16C"}.fa-instagram:before{content:"\\F16D"}.fa-flickr:before{content:"\\F16E"}.fa-adn:before{content:"\\F170"}.fa-bitbucket:before{content:"\\F171"}.fa-bitbucket-square:before{content:"\\F172"}.fa-tumblr:before{content:"\\F173"}.fa-tumblr-square:before{content:"\\F174"}.fa-long-arrow-down:before{content:"\\F175"}.fa-long-arrow-up:before{content:"\\F176"}.fa-long-arrow-left:before{content:"\\F177"}.fa-long-arrow-right:before{content:"\\F178"}.fa-apple:before{content:"\\F179"}.fa-windows:before{content:"\\F17A"}.fa-android:before{content:"\\F17B"}.fa-linux:before{content:"\\F17C"}.fa-dribbble:before{content:"\\F17D"}.fa-skype:before{content:"\\F17E"}.fa-foursquare:before{content:"\\F180"}.fa-trello:before{content:"\\F181"}.fa-female:before{content:"\\F182"}.fa-male:before{content:"\\F183"}.fa-gittip:before,.fa-gratipay:before{content:"\\F184"}.fa-sun-o:before{content:"\\F185"}.fa-moon-o:before{content:"\\F186"}.fa-archive:before{content:"\\F187"}.fa-bug:before{content:"\\F188"}.fa-vk:before{content:"\\F189"}.fa-weibo:before{content:"\\F18A"}.fa-renren:before{content:"\\F18B"}.fa-pagelines:before{content:"\\F18C"}.fa-stack-exchange:before{content:"\\F18D"}.fa-arrow-circle-o-right:before{content:"\\F18E"}.fa-arrow-circle-o-left:before{content:"\\F190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\\F191"}.fa-dot-circle-o:before{content:"\\F192"}.fa-wheelchair:before{content:"\\F193"}.fa-vimeo-square:before{content:"\\F194"}.fa-try:before,.fa-turkish-lira:before{content:"\\F195"}.fa-plus-square-o:before{content:"\\F196"}.fa-space-shuttle:before{content:"\\F197"}.fa-slack:before{content:"\\F198"}.fa-envelope-square:before{content:"\\F199"}.fa-wordpress:before{content:"\\F19A"}.fa-openid:before{content:"\\F19B"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\\F19C"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\\F19D"}.fa-yahoo:before{content:"\\F19E"}.fa-google:before{content:"\\F1A0"}.fa-reddit:before{content:"\\F1A1"}.fa-reddit-square:before{content:"\\F1A2"}.fa-stumbleupon-circle:before{content:"\\F1A3"}.fa-stumbleupon:before{content:"\\F1A4"}.fa-delicious:before{content:"\\F1A5"}.fa-digg:before{content:"\\F1A6"}.fa-pied-piper-pp:before{content:"\\F1A7"}.fa-pied-piper-alt:before{content:"\\F1A8"}.fa-drupal:before{content:"\\F1A9"}.fa-joomla:before{content:"\\F1AA"}.fa-language:before{content:"\\F1AB"}.fa-fax:before{content:"\\F1AC"}.fa-building:before{content:"\\F1AD"}.fa-child:before{content:"\\F1AE"}.fa-paw:before{content:"\\F1B0"}.fa-spoon:before{content:"\\F1B1"}.fa-cube:before{content:"\\F1B2"}.fa-cubes:before{content:"\\F1B3"}.fa-behance:before{content:"\\F1B4"}.fa-behance-square:before{content:"\\F1B5"}.fa-steam:before{content:"\\F1B6"}.fa-steam-square:before{content:"\\F1B7"}.fa-recycle:before{content:"\\F1B8"}.fa-automobile:before,.fa-car:before{content:"\\F1B9"}.fa-cab:before,.fa-taxi:before{content:"\\F1BA"}.fa-tree:before{content:"\\F1BB"}.fa-spotify:before{content:"\\F1BC"}.fa-deviantart:before{content:"\\F1BD"}.fa-soundcloud:before{content:"\\F1BE"}.fa-database:before{content:"\\F1C0"}.fa-file-pdf-o:before{content:"\\F1C1"}.fa-file-word-o:before{content:"\\F1C2"}.fa-file-excel-o:before{content:"\\F1C3"}.fa-file-powerpoint-o:before{content:"\\F1C4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\\F1C5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\\F1C6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\\F1C7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\\F1C8"}.fa-file-code-o:before{content:"\\F1C9"}.fa-vine:before{content:"\\F1CA"}.fa-codepen:before{content:"\\F1CB"}.fa-jsfiddle:before{content:"\\F1CC"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\\F1CD"}.fa-circle-o-notch:before{content:"\\F1CE"}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:"\\F1D0"}.fa-empire:before,.fa-ge:before{content:"\\F1D1"}.fa-git-square:before{content:"\\F1D2"}.fa-git:before{content:"\\F1D3"}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:"\\F1D4"}.fa-tencent-weibo:before{content:"\\F1D5"}.fa-qq:before{content:"\\F1D6"}.fa-wechat:before,.fa-weixin:before{content:"\\F1D7"}.fa-paper-plane:before,.fa-send:before{content:"\\F1D8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\\F1D9"}.fa-history:before{content:"\\F1DA"}.fa-circle-thin:before{content:"\\F1DB"}.fa-header:before{content:"\\F1DC"}.fa-paragraph:before{content:"\\F1DD"}.fa-sliders:before{content:"\\F1DE"}.fa-share-alt:before{content:"\\F1E0"}.fa-share-alt-square:before{content:"\\F1E1"}.fa-bomb:before{content:"\\F1E2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\\F1E3"}.fa-tty:before{content:"\\F1E4"}.fa-binoculars:before{content:"\\F1E5"}.fa-plug:before{content:"\\F1E6"}.fa-slideshare:before{content:"\\F1E7"}.fa-twitch:before{content:"\\F1E8"}.fa-yelp:before{content:"\\F1E9"}.fa-newspaper-o:before{content:"\\F1EA"}.fa-wifi:before{content:"\\F1EB"}.fa-calculator:before{content:"\\F1EC"}.fa-paypal:before{content:"\\F1ED"}.fa-google-wallet:before{content:"\\F1EE"}.fa-cc-visa:before{content:"\\F1F0"}.fa-cc-mastercard:before{content:"\\F1F1"}.fa-cc-discover:before{content:"\\F1F2"}.fa-cc-amex:before{content:"\\F1F3"}.fa-cc-paypal:before{content:"\\F1F4"}.fa-cc-stripe:before{content:"\\F1F5"}.fa-bell-slash:before{content:"\\F1F6"}.fa-bell-slash-o:before{content:"\\F1F7"}.fa-trash:before{content:"\\F1F8"}.fa-copyright:before{content:"\\F1F9"}.fa-at:before{content:"\\F1FA"}.fa-eyedropper:before{content:"\\F1FB"}.fa-paint-brush:before{content:"\\F1FC"}.fa-birthday-cake:before{content:"\\F1FD"}.fa-area-chart:before{content:"\\F1FE"}.fa-pie-chart:before{content:"\\F200"}.fa-line-chart:before{content:"\\F201"}.fa-lastfm:before{content:"\\F202"}.fa-lastfm-square:before{content:"\\F203"}.fa-toggle-off:before{content:"\\F204"}.fa-toggle-on:before{content:"\\F205"}.fa-bicycle:before{content:"\\F206"}.fa-bus:before{content:"\\F207"}.fa-ioxhost:before{content:"\\F208"}.fa-angellist:before{content:"\\F209"}.fa-cc:before{content:"\\F20A"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\\F20B"}.fa-meanpath:before{content:"\\F20C"}.fa-buysellads:before{content:"\\F20D"}.fa-connectdevelop:before{content:"\\F20E"}.fa-dashcube:before{content:"\\F210"}.fa-forumbee:before{content:"\\F211"}.fa-leanpub:before{content:"\\F212"}.fa-sellsy:before{content:"\\F213"}.fa-shirtsinbulk:before{content:"\\F214"}.fa-simplybuilt:before{content:"\\F215"}.fa-skyatlas:before{content:"\\F216"}.fa-cart-plus:before{content:"\\F217"}.fa-cart-arrow-down:before{content:"\\F218"}.fa-diamond:before{content:"\\F219"}.fa-ship:before{content:"\\F21A"}.fa-user-secret:before{content:"\\F21B"}.fa-motorcycle:before{content:"\\F21C"}.fa-street-view:before{content:"\\F21D"}.fa-heartbeat:before{content:"\\F21E"}.fa-venus:before{content:"\\F221"}.fa-mars:before{content:"\\F222"}.fa-mercury:before{content:"\\F223"}.fa-intersex:before,.fa-transgender:before{content:"\\F224"}.fa-transgender-alt:before{content:"\\F225"}.fa-venus-double:before{content:"\\F226"}.fa-mars-double:before{content:"\\F227"}.fa-venus-mars:before{content:"\\F228"}.fa-mars-stroke:before{content:"\\F229"}.fa-mars-stroke-v:before{content:"\\F22A"}.fa-mars-stroke-h:before{content:"\\F22B"}.fa-neuter:before{content:"\\F22C"}.fa-genderless:before{content:"\\F22D"}.fa-facebook-official:before{content:"\\F230"}.fa-pinterest-p:before{content:"\\F231"}.fa-whatsapp:before{content:"\\F232"}.fa-server:before{content:"\\F233"}.fa-user-plus:before{content:"\\F234"}.fa-user-times:before{content:"\\F235"}.fa-bed:before,.fa-hotel:before{content:"\\F236"}.fa-viacoin:before{content:"\\F237"}.fa-train:before{content:"\\F238"}.fa-subway:before{content:"\\F239"}.fa-medium:before{content:"\\F23A"}.fa-y-combinator:before,.fa-yc:before{content:"\\F23B"}.fa-optin-monster:before{content:"\\F23C"}.fa-opencart:before{content:"\\F23D"}.fa-expeditedssl:before{content:"\\F23E"}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:"\\F240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\\F241"}.fa-battery-2:before,.fa-battery-half:before{content:"\\F242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\\F243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\\F244"}.fa-mouse-pointer:before{content:"\\F245"}.fa-i-cursor:before{content:"\\F246"}.fa-object-group:before{content:"\\F247"}.fa-object-ungroup:before{content:"\\F248"}.fa-sticky-note:before{content:"\\F249"}.fa-sticky-note-o:before{content:"\\F24A"}.fa-cc-jcb:before{content:"\\F24B"}.fa-cc-diners-club:before{content:"\\F24C"}.fa-clone:before{content:"\\F24D"}.fa-balance-scale:before{content:"\\F24E"}.fa-hourglass-o:before{content:"\\F250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\\F251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\\F252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\\F253"}.fa-hourglass:before{content:"\\F254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\\F255"}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:"\\F256"}.fa-hand-scissors-o:before{content:"\\F257"}.fa-hand-lizard-o:before{content:"\\F258"}.fa-hand-spock-o:before{content:"\\F259"}.fa-hand-pointer-o:before{content:"\\F25A"}.fa-hand-peace-o:before{content:"\\F25B"}.fa-trademark:before{content:"\\F25C"}.fa-registered:before{content:"\\F25D"}.fa-creative-commons:before{content:"\\F25E"}.fa-gg:before{content:"\\F260"}.fa-gg-circle:before{content:"\\F261"}.fa-tripadvisor:before{content:"\\F262"}.fa-odnoklassniki:before{content:"\\F263"}.fa-odnoklassniki-square:before{content:"\\F264"}.fa-get-pocket:before{content:"\\F265"}.fa-wikipedia-w:before{content:"\\F266"}.fa-safari:before{content:"\\F267"}.fa-chrome:before{content:"\\F268"}.fa-firefox:before{content:"\\F269"}.fa-opera:before{content:"\\F26A"}.fa-internet-explorer:before{content:"\\F26B"}.fa-television:before,.fa-tv:before{content:"\\F26C"}.fa-contao:before{content:"\\F26D"}.fa-500px:before{content:"\\F26E"}.fa-amazon:before{content:"\\F270"}.fa-calendar-plus-o:before{content:"\\F271"}.fa-calendar-minus-o:before{content:"\\F272"}.fa-calendar-times-o:before{content:"\\F273"}.fa-calendar-check-o:before{content:"\\F274"}.fa-industry:before{content:"\\F275"}.fa-map-pin:before{content:"\\F276"}.fa-map-signs:before{content:"\\F277"}.fa-map-o:before{content:"\\F278"}.fa-map:before{content:"\\F279"}.fa-commenting:before{content:"\\F27A"}.fa-commenting-o:before{content:"\\F27B"}.fa-houzz:before{content:"\\F27C"}.fa-vimeo:before{content:"\\F27D"}.fa-black-tie:before{content:"\\F27E"}.fa-fonticons:before{content:"\\F280"}.fa-reddit-alien:before{content:"\\F281"}.fa-edge:before{content:"\\F282"}.fa-credit-card-alt:before{content:"\\F283"}.fa-codiepie:before{content:"\\F284"}.fa-modx:before{content:"\\F285"}.fa-fort-awesome:before{content:"\\F286"}.fa-usb:before{content:"\\F287"}.fa-product-hunt:before{content:"\\F288"}.fa-mixcloud:before{content:"\\F289"}.fa-scribd:before{content:"\\F28A"}.fa-pause-circle:before{content:"\\F28B"}.fa-pause-circle-o:before{content:"\\F28C"}.fa-stop-circle:before{content:"\\F28D"}.fa-stop-circle-o:before{content:"\\F28E"}.fa-shopping-bag:before{content:"\\F290"}.fa-shopping-basket:before{content:"\\F291"}.fa-hashtag:before{content:"\\F292"}.fa-bluetooth:before{content:"\\F293"}.fa-bluetooth-b:before{content:"\\F294"}.fa-percent:before{content:"\\F295"}.fa-gitlab:before{content:"\\F296"}.fa-wpbeginner:before{content:"\\F297"}.fa-wpforms:before{content:"\\F298"}.fa-envira:before{content:"\\F299"}.fa-universal-access:before{content:"\\F29A"}.fa-wheelchair-alt:before{content:"\\F29B"}.fa-question-circle-o:before{content:"\\F29C"}.fa-blind:before{content:"\\F29D"}.fa-audio-description:before{content:"\\F29E"}.fa-volume-control-phone:before{content:"\\F2A0"}.fa-braille:before{content:"\\F2A1"}.fa-assistive-listening-systems:before{content:"\\F2A2"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:"\\F2A3"}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:"\\F2A4"}.fa-glide:before{content:"\\F2A5"}.fa-glide-g:before{content:"\\F2A6"}.fa-sign-language:before,.fa-signing:before{content:"\\F2A7"}.fa-low-vision:before{content:"\\F2A8"}.fa-viadeo:before{content:"\\F2A9"}.fa-viadeo-square:before{content:"\\F2AA"}.fa-snapchat:before{content:"\\F2AB"}.fa-snapchat-ghost:before{content:"\\F2AC"}.fa-snapchat-square:before{content:"\\F2AD"}.fa-pied-piper:before{content:"\\F2AE"}.fa-first-order:before{content:"\\F2B0"}.fa-yoast:before{content:"\\F2B1"}.fa-themeisle:before{content:"\\F2B2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\\F2B3"}.fa-fa:before,.fa-font-awesome:before{content:"\\F2B4"}.fa-handshake-o:before{content:"\\F2B5"}.fa-envelope-open:before{content:"\\F2B6"}.fa-envelope-open-o:before{content:"\\F2B7"}.fa-linode:before{content:"\\F2B8"}.fa-address-book:before{content:"\\F2B9"}.fa-address-book-o:before{content:"\\F2BA"}.fa-address-card:before,.fa-vcard:before{content:"\\F2BB"}.fa-address-card-o:before,.fa-vcard-o:before{content:"\\F2BC"}.fa-user-circle:before{content:"\\F2BD"}.fa-user-circle-o:before{content:"\\F2BE"}.fa-user-o:before{content:"\\F2C0"}.fa-id-badge:before{content:"\\F2C1"}.fa-drivers-license:before,.fa-id-card:before{content:"\\F2C2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\\F2C3"}.fa-quora:before{content:"\\F2C4"}.fa-free-code-camp:before{content:"\\F2C5"}.fa-telegram:before{content:"\\F2C6"}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:"\\F2C7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\\F2C8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\\F2C9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\\F2CA"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\\F2CB"}.fa-shower:before{content:"\\F2CC"}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:"\\F2CD"}.fa-podcast:before{content:"\\F2CE"}.fa-window-maximize:before{content:"\\F2D0"}.fa-window-minimize:before{content:"\\F2D1"}.fa-window-restore:before{content:"\\F2D2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\\F2D3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\\F2D4"}.fa-bandcamp:before{content:"\\F2D5"}.fa-grav:before{content:"\\F2D6"}.fa-etsy:before{content:"\\F2D7"}.fa-imdb:before{content:"\\F2D8"}.fa-ravelry:before{content:"\\F2D9"}.fa-eercast:before{content:"\\F2DA"}.fa-microchip:before{content:"\\F2DB"}.fa-snowflake-o:before{content:"\\F2DC"}.fa-superpowers:before{content:"\\F2DD"}.fa-wpexplorer:before{content:"\\F2DE"}.fa-meetup:before{content:"\\F2E0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}',""]); +},function(A,M,t){M=A.exports=t(138)(),M.push([A.id,'*,:after,:before{box-sizing:border-box}body{font-family:Lato,sans-serif;font-size:15px;line-height:1.42857143;color:#8e8e8e;background-color:#edecec}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#46a5e0}a,a:focus,a:hover{text-decoration:none}a:focus,a:hover{color:#1f7fba}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#edecec;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:21px;margin-bottom:21px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:15px;text-align:left;background-color:#fff;border:1px solid transparent;border-radius:4px;box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9.5px 0;overflow:hidden;background-color:rgba(0,0,0,.08)}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#8e8e8e;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#333;background-color:rgba(0,0,0,.05)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#333;text-decoration:none;outline:0;background-color:rgba(0,0,0,.075)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#e4e4e4}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:13px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu>li>a{text-align:right}.navbar-right .dropdown-menu-left{left:0;right:auto}}.modal,.modal-open{overflow:hidden}.modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translateY(-25%);transform:translateY(-25%);-webkit-transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0);transform:translate(0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid transparent;border-radius:6px;box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:rgba(0,0,0,.1)}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:30px 35px 0;border-bottom:1px solid transparent}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:transparent}.modal-body{position:relative;padding:30px 35px}.modal-footer{padding:30px 35px;text-align:right;border-top:1px solid transparent}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:400px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Lato,sans-serif;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:13px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}@-ms-viewport{width:device-width}.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:active,:focus{outline:0}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body,html{min-height:100%}a{-webkit-transition:color;transition:color;-webkit-transition-duration:.3s;transition-duration:.3s}button{border:0}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translateY(-20px)}to{opacity:1;-webkit-transform:translateY(0)}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translateY(20px)}to{opacity:1;-webkit-transform:translateY(0)}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1;-webkit-transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(20px)}}@keyframes fadeOutDown{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(20px)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutUp{0%{opacity:1;-webkit-transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(-20px)}}@keyframes fadeOutUp{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-20px)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.text-center{text-align:center!important}.text-left{text-align:left!important}.text-right{text-align:right!important}.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.row:after,.row:before{content:" ";display:table}.clearfix:after,.container-fluid:after,.container:after,.modal-footer:after,.modal-header:after,.row:after{clear:both}.pull-right{float:right!important}.pull-left{float:left!important}.p-relative{position:relative}.m-0{margin:0!important}.m-t-0{margin-top:0!important}.m-b-0{margin-bottom:0!important}.m-l-0{margin-left:0!important}.m-r-0{margin-right:0!important}.m-5{margin:5px!important}.m-t-5{margin-top:5px!important}.m-b-5{margin-bottom:5px!important}.m-l-5{margin-left:5px!important}.m-r-5{margin-right:5px!important}.m-10{margin:10px!important}.m-t-10{margin-top:10px!important}.m-b-10{margin-bottom:10px!important}.m-l-10{margin-left:10px!important}.m-r-10{margin-right:10px!important}.m-15{margin:15px!important}.m-t-15{margin-top:15px!important}.m-b-15{margin-bottom:15px!important}.m-l-15{margin-left:15px!important}.m-r-15{margin-right:15px!important}.m-20{margin:20px!important}.m-t-20{margin-top:20px!important}.m-b-20{margin-bottom:20px!important}.m-l-20{margin-left:20px!important}.m-r-20{margin-right:20px!important}.m-25{margin:25px!important}.m-t-25{margin-top:25px!important}.m-b-25{margin-bottom:25px!important}.m-l-25{margin-left:25px!important}.m-r-25{margin-right:25px!important}.m-30{margin:30px!important}.m-t-30{margin-top:30px!important}.m-b-30{margin-bottom:30px!important}.m-l-30{margin-left:30px!important}.m-r-30{margin-right:30px!important}.p-0{padding:0!important}.p-t-0{padding-top:0!important}.p-b-0{padding-bottom:0!important}.p-l-0{padding-left:0!important}.p-r-0{padding-right:0!important}.p-5{padding:5px!important}.p-t-5{padding-top:5px!important}.p-b-5{padding-bottom:5px!important}.p-l-5{padding-left:5px!important}.p-r-5{padding-right:5px!important}.p-10{padding:10px!important}.p-t-10{padding-top:10px!important}.p-b-10{padding-bottom:10px!important}.p-l-10{padding-left:10px!important}.p-r-10{padding-right:10px!important}.p-15{padding:15px!important}.p-t-15{padding-top:15px!important}.p-b-15{padding-bottom:15px!important}.p-l-15{padding-left:15px!important}.p-r-15{padding-right:15px!important}.p-20{padding:20px!important}.p-t-20{padding-top:20px!important}.p-b-20{padding-bottom:20px!important}.p-l-20{padding-left:20px!important}.p-r-20{padding-right:20px!important}.p-25{padding:25px!important}.p-t-25{padding-top:25px!important}.p-b-25{padding-bottom:25px!important}.p-l-25{padding-left:25px!important}.p-r-25{padding-right:25px!important}.p-30{padding:30px!important}.p-t-30{padding-top:30px!important}.p-b-30{padding-bottom:30px!important}.p-l-30{padding-left:30px!important}.p-r-30{padding-right:30px!important}@font-face{font-family:Lato;src:url('+t(515)+') format("woff2"),url('+t(514)+') format("woff");font-weight:400;font-style:normal}.form-control{border:0;border-bottom:1px solid #eee;color:#32393f;padding:5px;width:100%;font-size:13px;background-color:transparent}select.form-control{-webkit-appearance:none;-moz-appearance:none;border-radius:0;background:url('+t(518)+') no-repeat bottom 7px right}.input-group{position:relative}.input-group:not(:last-child){margin-bottom:25px}.input-group label:not(.ig-label){font-size:13px;display:block;margin-bottom:10px}.ig-label{position:absolute;text-align:center;bottom:7px;left:0;width:100%;-webkit-transition:all;transition:all;-webkit-transition-duration:.25s;transition-duration:.25s;padding:2px 0 3px;border-radius:2px;font-weight:400}.ig-helpers{z-index:1;width:100%;left:0}.ig-helpers,.ig-helpers:after,.ig-helpers:before{position:absolute;height:2px;bottom:0}.ig-helpers:after,.ig-helpers:before{content:"";width:0;-webkit-transition:all;transition:all;-webkit-transition-duration:.25s;transition-duration:.25s;background-color:#03a9f4}.ig-helpers:before{left:50%}.ig-helpers:after{right:50%}.ig-text{width:100%;height:40px;border:0;background:transparent;text-align:center;position:relative;z-index:1;border-bottom:1px solid #eee;color:#32393f;font-size:13px}.ig-text:focus+.ig-helpers:after,.ig-text:focus+.ig-helpers:before{width:50%}.ig-text:disabled~.ig-label,.ig-text:focus~.ig-label,.ig-text:valid~.ig-label{bottom:35px;font-size:13px;z-index:1}.ig-text:disabled{opacity:.5;filter:alpha(opacity=50)}.ig-dark .ig-text{color:#fff;border-color:hsla(0,0%,100%,.1)}.ig-dark .ig-helpers:after,.ig-dark .ig-helpers:before{background-color:#dfdfdf;height:1px}.ig-left .ig-label,.ig-left .ig-text{text-align:left}.ig-error .ig-label{color:#e23f3f}.ig-error .ig-helpers i:first-child,.ig-error .ig-helpers i:first-child:after,.ig-error .ig-helpers i:first-child:before{background:rgba(226,63,63,.43)}.ig-error .ig-helpers i:last-child,.ig-error .ig-helpers i:last-child:after,.ig-error .ig-helpers i:last-child:before{background:#e23f3f!important}.ig-error:after{content:"\\F05A";font-family:FontAwesome;position:absolute;top:17px;right:9px;font-size:20px;color:#d33d3e}.ig-search:before{font-family:fontAwesome;content:"\\F002";font-size:15px;position:absolute;left:2px;top:8px}.ig-search .ig-text{padding-left:25px}.set-expire{border:1px solid #eee;margin:35px 0 30px}.set-expire-item{padding:9px 5px 3px;position:relative;display:table-cell;width:1%;text-align:center}.set-expire-item:not(:last-child){border-right:1px solid #eee}.set-expire-title{font-size:10px;text-transform:uppercase}.set-expire-value{display:inline-block;overflow:hidden;position:relative;left:-8px}.set-expire-value input{font-size:20px;text-align:center;position:relative;right:-15px;border:0;color:#333;padding:0;height:25px;width:100%;font-weight:400}.set-expire-decrease,.set-expire-increase{position:absolute;width:20px;height:20px;background:url('+t(516)+') no-repeat 50%;background-size:85%;left:50%;margin-left:-10px;opacity:.2;filter:alpha(opacity=20);cursor:pointer}.set-expire-decrease:hover,.set-expire-increase:hover{opacity:.5;filter:alpha(opacity=50)}.set-expire-increase{top:-25px}.set-expire-decrease{bottom:-27px;-webkit-transform:rotate(-180deg);transform:rotate(-180deg)}.btn{border:0;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:2px;text-align:center;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}.btn:focus,.btn:hover{opacity:.9;filter:alpha(opacity=90)}.btn-block{display:block;width:100%}.btn-link{color:#545454;background-color:#eee}.btn-link:focus,.btn-link:hover{color:#545454;background-color:#dfdfdf}.btn-danger{color:#fff;background-color:#ff726f}.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#ff5450}.btn-primary{color:#fff;background-color:#50b2ff}.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#31a5ff}.btn-success{color:#fff;background-color:#33d46f}.btn-success:focus,.btn-success:hover{color:#fff;background-color:#28c061}.close{right:15px;font-weight:400;opacity:1;font-size:18px;position:absolute;text-align:center;top:16px;z-index:1;padding:0;border:0;background-color:transparent}.close span{width:25px;height:25px;display:block;border-radius:50%;line-height:24px;text-shadow:none}.close:not(.close-alt) span{background-color:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.8)}.close:not(.close-alt):focus span,.close:not(.close-alt):hover span{background-color:hsla(0,0%,100%,.2);color:#fff}.close-alt span{background-color:#efefef;color:#989898}.close-alt:focus span,.close-alt:hover span{background-color:#e8e8e8;color:#7b7b7b}.hidden{display:none!important}.copy-text input{width:100%;border-radius:1px;border:1px solid #eee;padding:7px 12px;font-size:13px;line-height:100%;cursor:text;-webkit-transition:border-color;transition:border-color;-webkit-transition-duration:.3s;transition-duration:.3s}.copy-text input:hover{border-color:#e1e1e1}.share-availability{margin-bottom:40px}.share-availability:after,.share-availability:before{position:absolute;bottom:-30px;font-size:10px}.share-availability:before{content:"01 Sec";left:0}.share-availability:after{content:"7 days";right:0}.login{height:100vh;min-height:500px;background:#32393f;text-align:center}.login:before{height:calc(100% - 110px);width:1px;content:""}.l-wrap,.login:before{display:inline-block;vertical-align:middle}.l-wrap{width:80%;max-width:500px;margin-top:-50px}.l-wrap.toggled{display:inline-block}.l-wrap .input-group:not(:last-child){margin-bottom:40px}.l-footer{height:110px;padding:0 50px}.lf-logo{float:right}.lf-logo img{width:40px}.lf-server{float:left;color:hsla(0,0%,100%,.4);font-size:20px;font-weight:400;padding-top:40px}@media (max-width:768px){.lf-logo,.lf-server{float:none;display:block;text-align:center;width:100%}.lf-logo{margin-bottom:5px}.lf-server{font-size:15px}}.lw-btn{width:50px;height:50px;border:1px solid #fff;display:inline-block;border-radius:50%;font-size:22px;color:#fff;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;opacity:.3;background-color:transparent;line-height:45px;padding:0}.lw-btn:hover{color:#fff;opacity:.8;border-color:#fff}.lw-btn i{display:block;width:100%;padding-left:3px}input:-webkit-autofill{-webkit-box-shadow:0 0 0 50px #32393f inset!important;-webkit-text-fill-color:#fff!important}.fe-header{padding:45px 55px 20px}@media (min-width:992px){.fe-header{position:relative}}@media (max-width:667px){.fe-header{padding:25px 25px 20px}}.fe-header h2{font-size:16px;font-weight:400;margin:0}.fe-header h2>span{margin-bottom:7px;display:inline-block}.fe-header h2>span:not(:first-child):before{content:"/";margin:0 4px;color:#8e8e8e}.fe-header p{margin-top:7px}.feh-usage{margin-top:12px;max-width:285px}@media (max-width:667px){.feh-usage{max-width:100%;font-size:12px}}.feh-usage>ul{margin-top:7px;list-style:none;padding:0}.feh-usage>ul>li{padding-right:0;display:inline-block}.fehu-chart{height:5px;background:#eee;position:relative;border-radius:2px;overflow:hidden}.fehu-chart>div{position:absolute;left:0;height:100%;background:#46a5e0}.feh-actions{list-style:none;padding:0;margin:0;position:absolute;right:35px;top:30px;z-index:11}@media (max-width:991px){.feh-actions{top:7px;right:10px;position:fixed}}.feh-actions>li{display:inline-block;text-align:right;vertical-align:top;line-height:100%}.feh-actions>li>.btn-group>button,.feh-actions>li>a{display:block;height:45px;min-width:45px;text-align:center;border-radius:50%;padding:0;border:0;background:none}@media (min-width:992px){.feh-actions>li>.btn-group>button,.feh-actions>li>a{color:#7b7b7b;font-size:21px;line-height:45px;-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}.feh-actions>li>.btn-group>button:hover,.feh-actions>li>a:hover{background:rgba(0,0,0,.09)}}@media (max-width:991px){.feh-actions>li>.btn-group>button,.feh-actions>li>a{background:url('+t(237)+') no-repeat 50%}.feh-actions>li>.btn-group>button .fa-reorder,.feh-actions>li>a .fa-reorder{display:none}}@media (max-width:991px){.fe-header-mobile{background-color:#32393f;padding:10px 50px 9px 12px;text-align:center;position:fixed;z-index:10;box-shadow:0 0 10px rgba(0,0,0,.3);left:0;top:0;width:100%}.fe-header-mobile .mh-logo{height:35px;position:relative;top:4px}.feh-trigger{width:41px;height:41px;cursor:pointer;float:left;position:relative;text-align:center}.feh-trigger:after,.feh-trigger:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;border-radius:50%}.feh-trigger:after{z-index:1}.feh-trigger:before{background:hsla(0,0%,100%,.1);-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transform:scale(0);transform:scale(0)}.feht-toggled:before{-webkit-transform:scale(1);transform:scale(1)}.feht-toggled .feht-lines{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.feht-toggled .feht-lines>div.top{width:12px;transform:translateX(8px) translateY(1px) rotate(45deg);-webkit-transform:translateX(8px) translateY(1px) rotate(45deg)}.feht-toggled .feht-lines>div.bottom{width:12px;transform:translateX(8px) translateY(-1px) rotate(-45deg);-webkit-transform:translateX(8px) translateY(-1px) rotate(-45deg)}.feht-lines,.feht-lines>div{-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}.feht-lines{width:18px;height:12px;display:inline-block;margin-top:14px}.feht-lines>div{background-color:#eaeaea;width:18px;height:2px}.feht-lines>div.center{margin:3px 0}}.fe-sidebar{width:300px;background-color:#32393f;position:fixed;height:100%;overflow:hidden;padding:35px}@media (min-width:992px){.fe-sidebar{-webkit-transform:translateZ(0);transform:translateZ(0)}}@media (max-width:991px){.fe-sidebar{padding-top:85px;z-index:9;box-shadow:0 0 10px rgba(0,0,0,.65);-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s;-webkit-transform:translate3d(-315px,0,0);transform:translate3d(-315px,0,0)}.fe-sidebar.toggled{-webkit-transform:translateZ(0);transform:translateZ(0)}}.fe-sidebar a{color:hsla(0,0%,100%,.58)}.fe-sidebar a:hover{color:#fff}.fes-header{margin-bottom:40px}.fes-header h2,.fes-header img{float:left}.fes-header h2{margin:13px 0 0 10px;font-weight:400}.fes-header img{width:32px}.fesl-inner{height:calc(100vh - 260px);overflow:auto;padding:0;margin:0 -35px}.fesl-inner li{position:relative}.fesl-inner li>a{display:block;padding:10px 40px 12px 65px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fesl-inner li>a:before{font-family:FontAwesome;content:"\\F0A0";font-size:17px;position:absolute;top:10px;left:35px;opacity:.8;filter:alpha(opacity=80)}.fesl-inner li>a.fesli-loading:before{content:"";width:20px;height:20px;border-radius:50%;-webkit-animation-name:zoomIn;animation-name:zoomIn;-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-fill-mode:both;animation-fill-mode:both;border:2px solid hsla(0,0%,100%,.1);border-bottom-color:hsla(0,0%,100%,.5);position:absolute;z-index:1;-webkit-animation:zoomIn .25s,spin .7s .25s infinite linear;animation:zoomIn .25s,spin .7s .25s infinite linear;left:32px;top:0;bottom:0;margin:auto}.fesl-inner li.active{background-color:rgba(0,0,0,.2)}.fesl-inner li.active>a{color:#fff}.fesl-inner li:not(.active):hover{background-color:rgba(0,0,0,.1)}.fesl-inner li:not(.active):hover>a{color:#fff}.fesl-inner li:hover .fesli-trigger{opacity:.6;filter:alpha(opacity=60)}.fesl-inner li:hover .fesli-trigger:hover{opacity:1;filter:alpha(opacity=100)}.fesl-inner ul{list-style:none;padding:0;margin:0}.fesl-inner:hover .scrollbar-vertical{opacity:1}.fesli-trigger{filter:alpha(opacity=0);-webkit-transition:all;transition:all;-webkit-transition-duration:.2s;transition-duration:.2s;top:0;right:0;width:40px;cursor:pointer;background:url('+t(237)+') no-repeat 0}.fesli-trigger,.scrollbar-vertical{opacity:0;position:absolute;height:100%}.scrollbar-vertical{right:5px;width:4px;-webkit-transition:opacity;transition:opacity;-webkit-transition-duration:.3s;transition-duration:.3s}.scrollbar-vertical div{border-radius:1px!important;background-color:#6a6a6a!important}.fes-host{position:fixed;left:0;bottom:0;z-index:1;background:#32393f;color:hsla(0,0%,100%,.4);font-size:15px;font-weight:400;width:300px;padding:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fes-host>i{margin-right:10px}.fesl-row{padding-right:40px;padding-top:5px;padding-bottom:5px;position:relative}@media (min-width:668px){.fesl-row{display:flex;flex-flow:row nowrap;justify-content:space-between}}.fesl-row:after,.fesl-row:before{content:" ";display:table}.fesl-row:after{clear:both}@media (min-width:668px){header.fesl-row{margin-bottom:20px;border-bottom:1px solid #f0f0f0;padding-left:40px}header.fesl-row .fesl-item,header.fesl-row .fesli-sort{-webkit-transition:all;transition:all;-webkit-transition-duration:.3s;transition-duration:.3s}header.fesl-row .fesl-item{cursor:pointer;color:#8e8e8e;font-weight:500;margin-bottom:-5px}header.fesl-row .fesl-item>.fesli-sort{float:right;margin:4px 0 0;opacity:0;filter:alpha(opacity=0);color:#32393f;font-size:14px}header.fesl-row .fesl-item:hover:not(.fi-actions){background:#f5f5f5;color:#32393f}header.fesl-row .fesl-item:hover:not(.fi-actions)>.fesli-sort{opacity:.5;filter:alpha(opacity=50)}}@media (max-width:667px){header.fesl-row{display:none}}div.fesl-row{padding-left:85px;border-bottom:1px solid transparent;cursor:default}@media (max-width:667px){div.fesl-row{padding-left:70px;padding-right:45px}}div.fesl-row:nth-child(2n){background-color:#fafafa}div.fesl-row:hover{background-color:#fbf7dc}div.fesl-row[data-type]:before{font-family:fontAwesome;width:35px;height:35px;text-align:center;line-height:35px;position:absolute;border-radius:50%;font-size:16px;left:50px;top:9px;color:#fff}@media (max-width:667px){div.fesl-row[data-type]:before{left:20px}}@media (max-width:667px){div.fesl-row[data-type=folder] .fesl-item.fi-name{padding-top:10px;padding-bottom:7px}div.fesl-row[data-type=folder] .fesl-item.fi-modified,div.fesl-row[data-type=folder] .fesl-item.fi-size{display:none}}div.fesl-row[data-type=folder]:before{content:"\\F114";background-color:#a1d6dd}div.fesl-row[data-type=pdf]:before{content:"\\F1C1";background-color:#fa7775}div.fesl-row[data-type=zip]:before{content:"\\F1C6";background-color:#427089}div.fesl-row[data-type=audio]:before{content:"\\F1C7";background-color:#009688}div.fesl-row[data-type=code]:before{content:"\\F1C9";background-color:#997867}div.fesl-row[data-type=excel]:before{content:"\\F1C3";background-color:#64c866}div.fesl-row[data-type=image]:before{content:"\\F1C5";background-color:#f06292}div.fesl-row[data-type=video]:before{content:"\\F1C8";background-color:#f8c363}div.fesl-row[data-type=other]:before{content:"\\F016";background-color:#afafaf}div.fesl-row[data-type=text]:before{content:"\\F0F6";background-color:#8a8a8a}div.fesl-row[data-type=doc]:before{content:"\\F1C2";background-color:#2196f5}div.fesl-row[data-type=presentation]:before{content:"\\F1C4";background-color:#896ea6}div.fesl-row.fesl-loading:before{content:""}div.fesl-row.fesl-loading:after{content:"";width:20px;height:20px;border-radius:50%;-webkit-animation-name:zoomIn;animation-name:zoomIn;-webkit-animation-duration:.5s;animation-duration:.5s;-webkit-animation-fill-mode:both;animation-fill-mode:both;border:2px solid hsla(0,0%,100%,.5);border-bottom-color:#fff;position:absolute;z-index:1;-webkit-animation:zoomIn .25s,spin .7s .25s infinite linear;animation:zoomIn .25s,spin .7s .25s infinite linear;left:57px;top:17px}@media (max-width:667px){div.fesl-row.fesl-loading:after{left:27px}}.fesl-item{display:block}.fesl-item a{color:#818181}@media (min-width:668px){.fesl-item:not(.fi-actions){text-overflow:ellipsis;padding:10px 15px;white-space:nowrap;overflow:hidden}.fesl-item.fi-name{flex:3}.fesl-item.fi-size{width:140px}.fesl-item.fi-modified{width:190px}.fesl-item.fi-actions{width:40px}}@media (max-width:667px){.fesl-item{padding:0}.fesl-item.fi-name{width:100%;margin-bottom:3px}.fesl-item.fi-modified,.fesl-item.fi-size{font-size:12px;color:#b5b5b5;float:left}.fesl-item.fi-modified{max-width:72px;white-space:nowrap;overflow:hidden}.fesl-item.fi-size{margin-right:10px}.fesl-item.fi-actions{position:absolute;top:5px;right:10px}}.fia-toggle{height:36px;width:36px;background:transparent url('+t(517)+') no-repeat 50%;position:relative;top:3px;opacity:.4;filter:alpha(opacity=40)}.fia-toggle:hover{opacity:.7;filter:alpha(opacity=70)}.fi-actions .dropdown-menu{background-color:transparent;box-shadow:none;padding:0;right:38px;left:auto;margin:0;height:100%;text-align:right}.fi-actions .dropdown.open .dropdown-menu .fiad-action{right:0}.fiad-action{height:35px;width:35px;background:#ffc107;display:inline-block;border-radius:50%;text-align:center;line-height:35px;font-weight:400;position:relative;top:4px;margin-left:5px;-webkit-animation-name:fiad-action-anim;animation-name:fiad-action-anim;-webkit-transform-origin:center center;transform-origin:center center;-webkit-backface-visibility:none;backface-visibility:none;box-shadow:0 2px 4px rgba(0,0,0,.1)}.fiad-action:nth-child(2){-webkit-animation-duration:.1s;animation-duration:.1s}.fiad-action:first-child{-webkit-animation-duration:.25s;animation-duration:.25s}.fiad-action>i{font-size:14px;color:#fff}.fiad-action:hover{background-color:#f7b900}@-webkit-keyframes fiad-action-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0);right:-20px}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100);right:0}}@keyframes fiad-action-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0);right:-20px}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100);right:0}}.file-explorer{background-color:#fff;position:relative;height:100%}.file-explorer.toggled{height:100vh;overflow:hidden}.fe-body{min-height:100vh;overflow:auto}@media (min-width:992px){.fe-body{padding:0 0 40px 300px}}@media (max-width:991px){.fe-body{padding:75px 0 80px}}.feb-actions{position:fixed;bottom:30px;right:30px}.feb-actions .dropdown-menu{min-width:55px;width:55px;text-align:center;background:transparent;box-shadow:none;margin:0}.feb-actions.open .feba-btn{-webkit-transform:scale(1);transform:scale(1)}.feb-actions.open .feba-btn:first-child{-webkit-animation-name:feba-btn-anim;animation-name:feba-btn-anim;-webkit-animation-duration:.3s;animation-duration:.3s}.feb-actions.open .feba-btn:last-child{-webkit-animation-name:feba-btn-anim;animation-name:feba-btn-anim;-webkit-animation-duration:.1s;animation-duration:.1s}.feb-actions.open .feba-toggle{background:#ff403c}.feb-actions.open .feba-toggle>span{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.feba-toggle{width:55px;height:55px;line-height:55px;border-radius:50%;background:#ff726f;box-shadow:0 2px 3px rgba(0,0,0,.15);display:inline-block;text-align:center;border:0;padding:0}.feba-toggle span{display:inline-block;height:100%;width:100%}.feba-toggle i{color:#fff;font-size:17px;line-height:58px}.feba-toggle,.feba-toggle>span{-webkit-transition:all;transition:all;-webkit-transition-duration:.25s;transition-duration:.25s;-webkit-backface-visibility:hidden;backface-visibility:hidden}.feba-btn{width:40px;margin-top:10px;height:40px;border-radius:50%;text-align:center;display:inline-block;line-height:40px;box-shadow:0 2px 3px rgba(0,0,0,.15);-webkit-transform:scale(0);transform:scale(0);position:relative}.feba-btn,.feba-btn:focus,.feba-btn:hover{color:#fff}.feba-btn label{width:100%;height:100%;position:absolute;left:0;top:0;cursor:pointer}.feba-bucket{background:#ffc155}.feba-upload{background:#ffc107}@-webkit-keyframes feba-btn-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0)}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100)}}@keyframes feba-btn-anim{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0;filter:alpha(opacity=0)}to{-webkit-transform:scale(1);transform:scale(1);opacity:1;filter:alpha(opacity=100)}}.ie-warning{background-color:#ff5252;width:100%;height:100%;position:fixed;left:0;top:0;text-align:center}.ie-warning:before{width:1px;content:"";height:100%}.ie-warning .iw-inner,.ie-warning:before{display:inline-block;vertical-align:middle}.iw-inner{width:470px;height:300px;background-color:#fff;border-radius:5px;padding:40px;position:relative}.iw-inner ul{list-style:none;padding:0;margin:0;width:230px;margin-left:80px;margin-top:16px}.iw-inner ul>li{float:left}.iw-inner ul>li>a{display:block;padding:10px 15px 7px;font-size:14px;margin:0 1px;border-radius:3px}.iw-inner ul>li>a:hover{background:#eee}.iw-inner ul>li>a img{height:40px;margin-bottom:5px}.iwi-icon{color:#ff5252;font-size:40px;display:block;line-height:100%;margin-bottom:15px}.iwi-skip{position:absolute;left:0;bottom:-35px;width:100%;color:hsla(0,0%,100%,.6);cursor:pointer}.iwi-skip:hover{color:#fff}.dropdown-menu{padding:15px 0;top:0;margin-top:-1px}.dropdown-menu>li>a{padding:8px 20px;font-size:15px}.dropdown-menu>li>a>i{width:20px;position:relative;top:1px}.dropdown-menu-right>li>a{text-align:right}.alert{border:0;position:fixed;max-width:500px;margin:0;box-shadow:0 4px 5px rgba(0,0,0,.1);color:#fff;width:100%;right:20px;border-radius:3px;padding:17px 50px 17px 17px;z-index:10010;-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.alert:not(.progress){top:20px}@media (min-width:768px){.alert:not(.progress){left:50%;margin-left:-250px}}.alert.progress{bottom:20px;right:20px}.alert.alert-danger{background:#ff726f}.alert.alert-success{background:#33d46f}.alert.alert-info{background:#50b2ff}@media (max-width:767px){.alert{left:20px;width:calc(100% - 40px);max-width:100%}}.alert .progress{margin:10px 10px 8px 0;height:5px;box-shadow:none;border-radius:1px;background-color:#50b2ff;border-radius:2px;overflow:hidden}.alert .progress-bar{box-shadow:none;background-color:#fff;height:100%}.alert .close{position:absolute;top:15px}@media (min-width:768px){.modal{text-align:center}.modal:before{content:"";height:100%;width:1px}.modal .modal-dialog,.modal:before{display:inline-block;vertical-align:middle}.modal .modal-dialog{text-align:left;margin:10px auto}}.modal-dark .modal-header{color:hsla(0,0%,100%,.4)}.modal-dark .modal-header small{color:hsla(0,0%,100%,.2)}.modal-dark .modal-content{background-color:#32393f}.modal-backdrop{-webkit-animation-name:fadeIn;animation-name:fadeIn;-webkit-animation-fill-mode:both;animation-fill-mode:both}.modal-backdrop,.modal-dialog{-webkit-animation-duration:.2s;animation-duration:.2s}.modal-dialog{-webkit-animation-name:zoomIn;animation-name:zoomIn;-webkit-animation-fill-mode:both;animation-fill-mode:both}.modal-header{color:#333;position:relative}.modal-header small{display:block;text-transform:none;font-size:12px;margin-top:5px;color:#a8a8a8}.modal-content{border-radius:3px;box-shadow:none}.modal-footer{padding:0 30px 30px}.modal-confirm .modal-dialog,.modal-footer{text-align:center}.mc-icon{margin:0 0 10px}.mc-icon>i{font-size:60px}.mci-red{color:#ff8f8f}.mci-amber{color:#ffc107}.mci-green{color:#64e096}.mc-text{color:#333}.mc-sub{color:#bdbdbd;margin-top:5px;font-size:13px}@media (max-width:767px){.modal-about{text-align:center}.modal-about .modal-dialog{max-width:400px;width:90%;margin:20px auto 0}}.ma-inner{display:flex;flex-direction:row;align-items:center;min-height:350px;position:relative}@media (min-width:768px){.ma-inner:before{content:"";width:150px;height:100%;top:0;left:0;position:absolute;border-radius:3px 0 0 3px;background-color:#23282c}}.mai-item:first-child{width:150px;text-align:center}.mai-item:last-child{flex:4;padding:30px}.maii-logo{width:70px;position:relative}.maii-list{list-style:none;padding:0}.maii-list>li{margin-bottom:15px}.maii-list>li div{color:hsla(0,0%,100%,.8);text-transform:uppercase;font-size:14px}.maii-list>li small{font-size:13px;color:hsla(0,0%,100%,.4)}.toggle-password{position:absolute;bottom:30px;right:35px;width:30px;height:30px;border:1px solid #eee;border-radius:0;text-align:center;cursor:pointer;z-index:10;background-color:#fff;padding-top:5px}.toggle-password.toggled{background:#eee}.pm-body{padding-bottom:30px}.pmb-header{margin-bottom:35px}.pmb-list{display:flex;flex-flow:row nowrap;align-items:center;justify-content:center;padding:10px 35px}.pmb-list:nth-child(2n){background-color:#f7f7f7}.pmb-list .form-control{padding-left:0;padding-right:0}header.pmb-list{margin:20px 0 10px}.pmbl-item{display:block;font-size:13px}.pmbl-item:first-child{flex:2}.pmbl-item:nth-child(2){margin:0 25px;width:150px}.pmbl-item:nth-child(3){width:70px}div.pmb-list select{border:0}div.pmb-list .pml-item:not(:last-child){padding:0 5px}.modal-create-bucket .modal-dialog{position:fixed;right:25px;bottom:95px;margin:0;height:110px}.modal-create-bucket .modal-content{width:100%;height:100%}',""]); },function(A,M,t){function I(A){return null===A||void 0===A}function g(A){return!(!A||"object"!=typeof A||"number"!=typeof A.length)&&("function"==typeof A.copy&&"function"==typeof A.slice&&!(A.length>0&&"number"!=typeof A[0]))}function e(A,M,t){var e,o;if(I(A)||I(M))return!1;if(A.prototype!==M.prototype)return!1;if(E(A))return!!E(M)&&(A=i.call(A),M=i.call(M),N(A,M,t));if(g(A)){if(!g(M))return!1;if(A.length!==M.length)return!1;for(e=0;e=0;e--)if(n[e]!=C[e])return!1;for(e=n.length-1;e>=0;e--)if(o=n[e],!N(A[o],M[o],t))return!1;return typeof A==typeof M}var i=Array.prototype.slice,T=t(280),E=t(279),N=A.exports=function(A,M,t){return t||(t={}),A===M||(A instanceof Date&&M instanceof Date?A.getTime()===M.getTime():!A||!M||"object"!=typeof A&&"object"!=typeof M?t.strict?A===M:A==M:e(A,M,t))}},function(A,M){function t(A){return"[object Arguments]"==Object.prototype.toString.call(A)}function I(A){return A&&"object"==typeof A&&"number"==typeof A.length&&Object.prototype.hasOwnProperty.call(A,"callee")&&!Object.prototype.propertyIsEnumerable.call(A,"callee")||!1}var g="[object Arguments]"==function(){return Object.prototype.toString.call(arguments)}();M=A.exports=g?t:I,M.supported=t,M.unsupported=I},function(A,M){function t(A){var M=[];for(var t in A)M.push(t);return M}M=A.exports="function"==typeof Object.keys?Object.keys:t,M.shim=t},function(A,M,t){"use strict";var I=t(141);A.exports=function(A,M){A.classList?A.classList.add(M):I(A)||(A.className=A.className+" "+M)}},function(A,M,t){"use strict";A.exports={addClass:t(281),removeClass:t(283),hasClass:t(141)}},function(A,M){"use strict";A.exports=function(A,M){A.classList?A.classList.remove(M):A.className=A.className.replace(new RegExp("(^|\\s)"+M+"(?:\\s|$)","g"),"$1").replace(/\s+/g," ").replace(/^\s*|\s*$/g,"")}},function(A,M,t){"use strict";var I=t(40),g=t(288);A.exports=function(A,M){return function(t){var e=t.currentTarget,i=t.target,T=g(e,A);T.some(function(A){return I(A,i)})&&M.call(this,t)}}},function(A,M,t){"use strict";var I=t(81),g=t(142),e=t(284);A.exports={on:I,off:g,filter:e}},function(A,M,t){"use strict";function I(A){return A.nodeName&&A.nodeName.toLowerCase()}function g(A){for(var M=(0,T.default)(A),t=A&&A.offsetParent;t&&"html"!==I(A)&&"static"===(0,N.default)(t,"position");)t=t.offsetParent;return t||M.documentElement}var e=t(58);M.__esModule=!0,M.default=g;var i=t(39),T=e.interopRequireDefault(i),E=t(82),N=e.interopRequireDefault(E);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A.nodeName&&A.nodeName.toLowerCase()}function g(A,M){var t,g={top:0,left:0};return"fixed"===(0,a.default)(A,"position")?t=A.getBoundingClientRect():(M=M||(0,N.default)(A),t=(0,T.default)(A),"html"!==I(M)&&(g=(0,T.default)(M)),g.top+=parseInt((0,a.default)(M,"borderTopWidth"),10)-(0,n.default)(M)||0,g.left+=parseInt((0,a.default)(M,"borderLeftWidth"),10)-(0,c.default)(M)||0),e._extends({},t,{top:t.top-g.top-(parseInt((0,a.default)(A,"marginTop"),10)||0),left:t.left-g.left-(parseInt((0,a.default)(A,"marginLeft"),10)||0)})}var e=t(58);M.__esModule=!0,M.default=g;var i=t(143),T=e.interopRequireDefault(i),E=t(286),N=e.interopRequireDefault(E),o=t(144),n=e.interopRequireDefault(o),C=t(289),c=e.interopRequireDefault(C),D=t(82),a=e.interopRequireDefault(D);A.exports=M.default},function(A,M){"use strict";var t=/^[\w-]*$/,I=Function.prototype.bind.call(Function.prototype.call,[].slice);A.exports=function(A,M){var g,e="#"===M[0],i="."===M[0],T=e||i?M.slice(1):M,E=t.test(T);return E?e?(A=A.getElementById?A:document,(g=A.getElementById(T))?[g]:[]):I(A.getElementsByClassName&&i?A.getElementsByClassName(T):A.getElementsByTagName(M)):I(A.querySelectorAll(M))}},function(A,M,t){"use strict";var I=t(57);A.exports=function(A,M){var t=I(A);return void 0===M?t?"pageXOffset"in t?t.pageXOffset:t.document.documentElement.scrollLeft:A.scrollLeft:void(t?t.scrollTo(M,"pageYOffset"in t?t.pageYOffset:t.document.documentElement.scrollTop):A.scrollLeft=M)}},function(A,M,t){"use strict";var I=t(58),g=t(145),e=I.interopRequireDefault(g),i=/^(top|right|bottom|left)$/,T=/^([+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/i;A.exports=function(A){if(!A)throw new TypeError("No Element passed to ` + "`" + `getComputedStyle()` + "`" + `");var M=A.ownerDocument;return"defaultView"in M?M.defaultView.opener?A.ownerDocument.defaultView.getComputedStyle(A,null):window.getComputedStyle(A,null):{getPropertyValue:function(M){var t=A.style;M=(0,e.default)(M),"float"==M&&(M="styleFloat");var I=A.currentStyle[M]||null;if(null==I&&t&&t[M]&&(I=t[M]),T.test(I)&&!i.test(M)){var g=t.left,E=A.runtimeStyle,N=E&&E.left;N&&(E.left=A.currentStyle.left),t.left="fontSize"===M?"1em":I,I=t.pixelLeft+"px",t.left=g,N&&(E.left=N)}return I}}}},function(A,M){"use strict";A.exports=function(A,M){return"removeProperty"in A.style?A.style.removeProperty(M):A.style.removeAttribute(M)}},function(A,M,t){"use strict";function I(){var A,M="",t={O:"otransitionend",Moz:"transitionend",Webkit:"webkitTransitionEnd",ms:"MSTransitionEnd"},I=document.createElement("div");for(var g in t)if(N.call(t,g)&&void 0!==I.style[g+"TransitionProperty"]){M="-"+g.toLowerCase()+"-",A=t[g];break}return A||void 0===I.style.transitionProperty||(A="transitionend"),{end:A,prefix:M}}var g,e,i,T,E=t(32),N=Object.prototype.hasOwnProperty,o="transform",n={};E&&(n=I(),o=n.prefix+o,i=n.prefix+"transition-property",e=n.prefix+"transition-duration",T=n.prefix+"transition-delay",g=n.prefix+"transition-timing-function"),A.exports={transform:o,end:n.end,property:i,timing:g,delay:T,duration:e}},function(A,M){"use strict";var t=/-(.)/g;A.exports=function(A){return A.replace(t,function(A,M){return M.toUpperCase()})}},function(A,M){"use strict";var t=/([A-Z])/g;A.exports=function(A){return A.replace(t,"-$1").toLowerCase()}},function(A,M,t){"use strict";var I=t(294),g=/^ms-/;A.exports=function(A){return I(A).replace(g,"-ms-")}},function(A,M){"use strict";function t(A){return A.replace(I,function(A,M){return M.toUpperCase()})}var I=/-(.)/g;A.exports=t},function(A,M,t){"use strict";function I(A){return g(A.replace(e,"ms-"))}var g=t(296),e=/^-ms-/;A.exports=I},function(A,M,t){"use strict";function I(A){return!!A&&("object"==typeof A||"function"==typeof A)&&"length"in A&&!("setInterval"in A)&&"number"!=typeof A.nodeType&&(Array.isArray(A)||"callee"in A||"item"in A)}function g(A){return I(A)?Array.isArray(A)?A.slice():e(A):[A]}var e=t(307);A.exports=g},function(A,M,t){"use strict";function I(A){var M=A.match(o);return M&&M[1].toLowerCase()}function g(A,M){var t=N;N?void 0:E(!1);var g=I(A),e=g&&T(g);if(e){t.innerHTML=e[1]+A+e[2];for(var o=e[0];o--;)t=t.lastChild}else t.innerHTML=A;var n=t.getElementsByTagName("script");n.length&&(M?void 0:E(!1),i(n).forEach(M));for(var C=i(t.childNodes);t.lastChild;)t.removeChild(t.lastChild);return C}var e=t(10),i=t(298),T=t(151),E=t(2),N=e.canUseDOM?document.createElement("div"):null,o=/^\s*<(\w+)/;A.exports=g},function(A,M){"use strict";function t(A){return A===window?{x:window.pageXOffset||document.documentElement.scrollLeft,y:window.pageYOffset||document.documentElement.scrollTop}:{x:A.scrollLeft,y:A.scrollTop}}A.exports=t},function(A,M){"use strict";function t(A){return A.replace(I,"-$1").toLowerCase()}var I=/([A-Z])/g;A.exports=t},function(A,M,t){"use strict";function I(A){return g(A).replace(e,"-ms-")}var g=t(301),e=/^ms-/;A.exports=I},function(A,M){"use strict";function t(A){return!(!A||!("function"==typeof Node?A instanceof Node:"object"==typeof A&&"number"==typeof A.nodeType&&"string"==typeof A.nodeName))}A.exports=t},function(A,M,t){"use strict";function I(A){return g(A)&&3==A.nodeType}var g=t(303);A.exports=I},function(A,M){"use strict";function t(A,M,t){if(!A)return null;var g={};for(var e in A)I.call(A,e)&&(g[e]=M.call(t,A[e],e,A));return g}var I=Object.prototype.hasOwnProperty;A.exports=t},function(A,M){"use strict";function t(A){var M={};return function(t){return M.hasOwnProperty(t)||(M[t]=A.call(this,t)),M[t]}}A.exports=t},function(A,M,t){"use strict";function I(A){var M=A.length;if(Array.isArray(A)||"object"!=typeof A&&"function"!=typeof A?g(!1):void 0,"number"!=typeof M?g(!1):void 0,0===M||M-1 in A?void 0:g(!1),A.hasOwnProperty)try{return Array.prototype.slice.call(A)}catch(A){}for(var t=Array(M),I=0;Io||N===o&&"application/"===M[T].substr(0,12))continue}M[T]=I}}})}var E=t(351),N=t(354).extname,o=/^\s*([^;\s]*)(?:;|\s|$)/,n=/^text\//i;M.charset=I,M.charsets={lookup:I},M.contentType=g,M.extension=e,M.extensions=Object.create(null),M.lookup=i,M.types=Object.create(null),T(M.extensions,M.types)},function(A,M){function t(A){throw new Error("Cannot find module '"+A+"'.")}t.keys=function(){return[]},t.resolve=t,A.exports=t,t.id=353},function(A,M,t){(function(A){function t(A,M){for(var t=0,I=A.length-1;I>=0;I--){var g=A[I];"."===g?A.splice(I,1):".."===g?(A.splice(I,1),t++):t&&(A.splice(I,1),t--)}if(M)for(;t--;t)A.unshift("..");return A}function I(A,M){if(A.filter)return A.filter(M);for(var t=[],I=0;I=-1&&!g;e--){var i=e>=0?arguments[e]:A.cwd();if("string"!=typeof i)throw new TypeError("Arguments to path.resolve must be strings");i&&(M=i+"/"+M,g="/"===i.charAt(0))}return M=t(I(M.split("/"),function(A){return!!A}),!g).join("/"),(g?"/":"")+M||"."},M.normalize=function(A){var g=M.isAbsolute(A),e="/"===i(A,-1);return A=t(I(A.split("/"),function(A){return!!A}),!g).join("/"),A||g||(A="."),A&&e&&(A+="/"),(g?"/":"")+A},M.isAbsolute=function(A){return"/"===A.charAt(0)},M.join=function(){var A=Array.prototype.slice.call(arguments,0);return M.normalize(I(A,function(A,M){if("string"!=typeof A)throw new TypeError("Arguments to path.join must be strings");return A}).join("/"))},M.relative=function(A,t){function I(A){for(var M=0;M=0&&""===A[t];t--);return M>t?[]:A.slice(M,t-M+1)}A=M.resolve(A).substr(1),t=M.resolve(t).substr(1);for(var g=I(A.split("/")),e=I(t.split("/")),i=Math.min(g.length,e.length),T=i,E=0;E=0;e--){var i=I[e]+g;if(i in M)return i}return!1}},function(A,M,t){"use strict";var I=t(496);M.extract=function(A){return A.split("?")[1]||""},M.parse=function(A){return"string"!=typeof A?{}:(A=A.trim().replace(/^(\?|#|&)/,""),A?A.split("&").reduce(function(A,M){var t=M.replace(/\+/g," ").split("="),I=t.shift(),g=t.length>0?t.join("="):void 0;return I=decodeURIComponent(I),g=void 0===g?null:decodeURIComponent(g),A.hasOwnProperty(I)?Array.isArray(A[I])?A[I].push(g):A[I]=[A[I],g]:A[I]=g,A},{}):{})},M.stringify=function(A){return A?Object.keys(A).sort().map(function(M){var t=A[M];return void 0===t?"":null===t?M:Array.isArray(t)?t.slice().sort().map(function(A){return I(M)+"="+I(A)}).join("&"):I(M)+"="+I(t)}).filter(function(A){return A.length>0}).join("&"):""}},function(A,M){"use strict";function t(A,M){return Object.prototype.hasOwnProperty.call(A,M)}A.exports=function(A,M,I,g){M=M||"&",I=I||"=";var e={};if("string"!=typeof A||0===A.length)return e;var i=/\+/g;A=A.split(M);var T=1e3;g&&"number"==typeof g.maxKeys&&(T=g.maxKeys);var E=A.length;T>0&&E>T&&(E=T);for(var N=0;N=0?(o=D.substr(0,a),n=D.substr(a+1)):(o=D,n=""),C=decodeURIComponent(o),c=decodeURIComponent(n),t(e,C)?Array.isArray(e[C])?e[C].push(c):e[C]=[e[C],c]:e[C]=c}return e}},function(A,M){"use strict";var t=function(A){switch(typeof A){case"string":return A;case"boolean":return A?"true":"false";case"number":return isFinite(A)?A:"";default:return""}};A.exports=function(A,M,I,g){return M=M||"&",I=I||"=",null===A&&(A=void 0),"object"==typeof A?Object.keys(A).map(function(g){var e=encodeURIComponent(t(g))+I;return Array.isArray(A[g])?A[g].map(function(A){return e+encodeURIComponent(t(A))}).join(M):e+encodeURIComponent(t(A[g]))}).join(M):g?encodeURIComponent(t(g))+I+encodeURIComponent(t(A)):""}},function(A,M,t){"use strict";M.decode=M.parse=t(358),M.encode=M.stringify=t(359)},function(A,M,t){(function(M){for(var I=t(355),g="undefined"==typeof window?M:window,e=["moz","webkit"],i="AnimationFrame",T=g["request"+i],E=g["cancel"+i]||g["cancelRequest"+i],N=0;!T&&N1)||(e=A,!1)}),e)return new Error("(children) "+I+" - Duplicate children detected of bsRole: "+e+". Only one child each allowed with the following bsRoles: "+M.join(", "))})}},A.exports=M.default},function(A,M,t){"use strict";function I(A){var M=[];return void 0===A?M:(i.default.forEach(A,function(A){M.push(A)}),M)}var g=t(6).default;M.__esModule=!0,M.default=I;var e=t(51),i=g(e);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}Object.defineProperty(M,"__esModule",{value:!0}),M.CopyToClipboard=void 0;var e=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){var M=A.style,t=g(A,["style"]),I=o({},M,{height:6,right:2,bottom:2,left:2,borderRadius:3});return C.default.createElement("div",o({style:I},t))}function i(A){var M=A.style,t=g(A,["style"]),I=o({},M,{width:6,right:2,bottom:2,top:2,borderRadius:3});return C.default.createElement("div",o({style:I},t))}function T(A){var M=A.style,t=g(A,["style"]),I=o({},M,{cursor:"pointer",borderRadius:"inherit",backgroundColor:"rgba(0,0,0,.2)"});return C.default.createElement("div",o({style:I},t))}function E(A){var M=A.style,t=g(A,["style"]),I=o({},M,{cursor:"pointer",borderRadius:"inherit",backgroundColor:"rgba(0,0,0,.2)"});return C.default.createElement("div",o({style:I},t))}function N(A){return C.default.createElement("div",A)}var o=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}var e=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=Object.assign||function(A){for(var M=1;M0||(this.setState({isDragActive:!1,isDragReject:!1}),this.props.onDragLeave&&this.props.onDragLeave.call(this,A))}},{key:"onDrop",value:function A(M){var t=this,I=this.props,A=I.onDrop,g=I.onDropAccepted,e=I.onDropRejected,i=I.multiple,T=I.disablePreview,E=(0,a.default)(M,i),N=[],o=[];M.preventDefault(),this.enterCounter=0,this.isFileDialogActive=!1,E.forEach(function(A){T||(A.preview=window.URL.createObjectURL(A)),t.fileAccepted(A)&&t.fileMatchSize(A)?N.push(A):o.push(A)}),A&&A.call(this,N,o,M),o.length>0&&e&&e.call(this,o,M),N.length>0&&g&&g.call(this,N,M),this.setState({isDragActive:!1,isDragReject:!1})}},{key:"onClick",value:function A(M){M.stopPropagation();var t=this.props,A=t.onClick,I=t.disableClick;I||(this.open(),A&&A.call(this,M))}},{key:"onFileDialogCancel",value:function A(){var A=this.props.onFileDialogCancel,M=this.fileInputEl,t=this.isFileDialogActive;A&&t&&setTimeout(function(){var I=M.files;I.length||(t=!1,A())},300)}},{key:"fileAccepted",value:function(A){return(0,c.default)(A,this.props.accept)}},{key:"fileMatchSize",value:function(A){return A.size<=this.props.maxSize&&A.size>=this.props.minSize}},{key:"allFilesAccepted",value:function(A){return A.every(this.fileAccepted)}},{key:"open",value:function(){this.isFileDialogActive=!0,this.fileInputEl.value=null,this.fileInputEl.click()}},{key:"render",value:function(){var A=this,M=this.props,t=M.accept,I=M.activeClassName,e=M.inputProps,i=M.multiple,T=M.name,N=M.rejectClassName,o=g(M,["accept","activeClassName","inputProps","multiple","name","rejectClassName"]),C=o.activeStyle,c=o.className,D=o.rejectStyle,a=o.style,Q=g(o,["activeStyle","className","rejectStyle","style"]),r=this.state,s=r.isDragActive,x=r.isDragReject;c=c||"",s&&I&&(c+=" "+I),x&&N&&(c+=" "+N),c||a||C||D||(a={width:200,height:200,borderWidth:2,borderColor:"#666",borderStyle:"dashed",borderRadius:5},C={borderStyle:"solid",backgroundColor:"#eee"},D={borderStyle:"solid",backgroundColor:"#ffdddd"});var j=void 0;j=C&&s?E({},a,C):D&&x?E({},a,D):E({},a);var y={accept:t,type:"file",style:{display:"none"},multiple:B&&i,ref:function(M){return A.fileInputEl=M},onChange:this.onDrop};T&&T.length&&(y.name=T);var u=["acceptedFiles","disablePreview","disableClick","onDropAccepted","onDropRejected","onFileDialogCancel","maxSize","minSize"],w=E({},Q);return u.forEach(function(A){return delete w[A]}),n.default.createElement("div",E({className:c,style:j},w,{onClick:this.onClick,onDragStart:this.onDragStart,onDragEnter:this.onDragEnter,onDragOver:this.onDragOver,onDragLeave:this.onDragLeave,onDrop:this.onDrop}),this.props.children,n.default.createElement("input",E({},e,y)))}}]),M}(n.default.Component);Q.defaultProps={disablePreview:!1,disableClick:!1,multiple:!0,maxSize:1/0,minSize:0},Q.propTypes={onClick:n.default.PropTypes.func,onDrop:n.default.PropTypes.func,onDropAccepted:n.default.PropTypes.func,onDropRejected:n.default.PropTypes.func,onDragStart:n.default.PropTypes.func,onDragEnter:n.default.PropTypes.func,onDragOver:n.default.PropTypes.func,onDragLeave:n.default.PropTypes.func,children:n.default.PropTypes.node,style:n.default.PropTypes.object,activeStyle:n.default.PropTypes.object,rejectStyle:n.default.PropTypes.object,className:n.default.PropTypes.string,activeClassName:n.default.PropTypes.string,rejectClassName:n.default.PropTypes.string,disablePreview:n.default.PropTypes.bool,disableClick:n.default.PropTypes.bool,onFileDialogCancel:n.default.PropTypes.func,inputProps:n.default.PropTypes.object,multiple:n.default.PropTypes.bool,accept:n.default.PropTypes.string,name:n.default.PropTypes.string,maxSize:n.default.PropTypes.number,minSize:n.default.PropTypes.number},M.default=Q,A.exports=M.default},function(M,t){M.exports=A},function(A,M){A.exports=function(A){function M(I){if(t[I])return t[I].exports;var g=t[I]={exports:{},id:I,loaded:!1};return A[I].call(g.exports,g,g.exports,M),g.loaded=!0,g.exports}var t={};return M.m=A,M.c=t,M.p="",M(0)}([function(A,M,t){"use strict";M.__esModule=!0,t(8),t(9),M.default=function(A,M){if(A&&M){var t=function(){var t=Array.isArray(M)?M:M.split(","),I=A.name||"",g=A.type||"",e=g.replace(/\/.*$/,"");return{v:t.some(function(A){var M=A.trim();return"."===M.charAt(0)?I.toLowerCase().endsWith(M.toLowerCase()):/\/\*$/.test(M)?e===M.replace(/\/.*$/,""):g===M})}}();if("object"==typeof t)return t.v}return!0},A.exports=M.default},function(A,M){var t=A.exports={version:"1.2.2"};"number"==typeof __e&&(__e=t)},function(A,M){var t=A.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=t)},function(A,M,t){var I=t(2),g=t(1),e=t(4),i=t(19),T="prototype",E=function(A,M){return function(){return A.apply(M,arguments)}},N=function(A,M,t){var o,n,C,c,D=A&N.G,a=A&N.P,B=D?I:A&N.S?I[M]||(I[M]={}):(I[M]||{})[T],Q=D?g:g[M]||(g[M]={});D&&(t=M);for(o in t)n=!(A&N.F)&&B&&o in B,C=(n?B:t)[o],c=A&N.B&&n?E(C,I):a&&"function"==typeof C?E(Function.call,C):C,B&&!n&&i(B,o,C),Q[o]!=C&&e(Q,o,c),a&&((Q[T]||(Q[T]={}))[o]=C)};I.core=g,N.F=1,N.G=2,N.S=4,N.P=8,N.B=16,N.W=32,A.exports=N},function(A,M,t){var I=t(5),g=t(18);A.exports=t(22)?function(A,M,t){return I.setDesc(A,M,g(1,t))}:function(A,M,t){return A[M]=t,A}},function(A,M){var t=Object;A.exports={create:t.create,getProto:t.getPrototypeOf,isEnum:{}.propertyIsEnumerable,getDesc:t.getOwnPropertyDescriptor,setDesc:t.defineProperty,setDescs:t.defineProperties,getKeys:t.keys,getNames:t.getOwnPropertyNames,getSymbols:t.getOwnPropertySymbols,each:[].forEach}},function(A,M){var t=0,I=Math.random();A.exports=function(A){return"Symbol(".concat(void 0===A?"":A,")_",(++t+I).toString(36))}},function(A,M,t){var I=t(20)("wks"),g=t(2).Symbol;A.exports=function(A){return I[A]||(I[A]=g&&g[A]||(g||t(6))("Symbol."+A))}},function(A,M,t){t(26),A.exports=t(1).Array.some},function(A,M,t){t(25),A.exports=t(1).String.endsWith},function(A,M){A.exports=function(A){if("function"!=typeof A)throw TypeError(A+" is not a function!");return A}},function(A,M){var t={}.toString;A.exports=function(A){return t.call(A).slice(8,-1)}},function(A,M,t){var I=t(10);A.exports=function(A,M,t){if(I(A),void 0===M)return A;switch(t){case 1:return function(t){return A.call(M,t)};case 2:return function(t,I){return A.call(M,t,I)};case 3:return function(t,I,g){return A.call(M,t,I,g)}}return function(){return A.apply(M,arguments)}}},function(A,M){A.exports=function(A){if(void 0==A)throw TypeError("Can't call method on "+A);return A}},function(A,M,t){A.exports=function(A){var M=/./;try{"/./"[A](M)}catch(I){try{return M[t(7)("match")]=!1,!"/./"[A](M)}catch(A){}}return!0}},function(A,M){A.exports=function(A){try{return!!A()}catch(A){return!0}}},function(A,M){A.exports=function(A){return"object"==typeof A?null!==A:"function"==typeof A}},function(A,M,t){var I=t(16),g=t(11),e=t(7)("match");A.exports=function(A){var M;return I(A)&&(void 0!==(M=A[e])?!!M:"RegExp"==g(A))}},function(A,M){A.exports=function(A,M){return{enumerable:!(1&A),configurable:!(2&A),writable:!(4&A),value:M}}},function(A,M,t){var I=t(2),g=t(4),e=t(6)("src"),i="toString",T=Function[i],E=(""+T).split(i);t(1).inspectSource=function(A){return T.call(A)},(A.exports=function(A,M,t,i){"function"==typeof t&&(g(t,e,A[M]?""+A[M]:E.join(String(M))),"name"in t||(t.name=M)),A===I?A[M]=t:(i||delete A[M],g(A,M,t))})(Function.prototype,i,function(){return"function"==typeof this&&this[e]||T.call(this)})},function(A,M,t){var I=t(2),g="__core-js_shared__",e=I[g]||(I[g]={});A.exports=function(A){return e[A]||(e[A]={})}},function(A,M,t){var I=t(17),g=t(13);A.exports=function(A,M,t){if(I(M))throw TypeError("String#"+t+" doesn't accept regex!");return String(g(A))}},function(A,M,t){A.exports=!t(15)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(A,M){var t=Math.ceil,I=Math.floor;A.exports=function(A){return isNaN(A=+A)?0:(A>0?I:t)(A)}},function(A,M,t){var I=t(23),g=Math.min;A.exports=function(A){return A>0?g(I(A),9007199254740991):0}},function(A,M,t){"use strict";var I=t(3),g=t(24),e=t(21),i="endsWith",T=""[i];I(I.P+I.F*t(14)(i),"String",{endsWith:function(A){var M=e(this,A,i),t=arguments,I=t.length>1?t[1]:void 0,E=g(M.length),N=void 0===I?E:Math.min(g(I),E),o=String(A);return T?T.call(M,o,N):M.slice(N-o.length,N)===o}})},function(A,M,t){var I=t(5),g=t(3),e=t(1).Array||Array,i={},T=function(A,M){I.each.call(A.split(","),function(A){void 0==M&&A in e?i[A]=e[A]:A in[]&&(i[A]=t(12)(Function.call,[][A],M))})};T("pop,reverse,shift,keys,values,entries",1),T("indexOf,every,some,forEach,map,filter,find,findIndex,includes",3),T("join,slice,concat,push,splice,unshift,sort,lastIndexOf,reduce,reduceRight,copyWithin,fill"),g(g.S,"Array",i)}])},function(A,M){"use strict";function t(A){var M=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],t=[];if(A.dataTransfer){var I=A.dataTransfer;I.files&&I.files.length?t=I.files:I.items&&I.items.length&&(t=I.items)}else A.target&&A.target.files&&(t=A.target.files);return t.length>0&&(t=M?t:[t[0]]),Array.prototype.slice.call(t)}Object.defineProperty(M,"__esModule",{value:!0}),M.default=t,A.exports=M.default}])})},function(A,M,t){"use strict";function I(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function g(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}var e=function(){function A(A,M){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{},t=M.hideSiblingNodes,I=void 0===t||t,e=M.handleContainerOverflow,i=void 0===e||e;g(this,A),this.hideSiblingNodes=I,this.handleContainerOverflow=i,this.modals=[],this.containers=[],this.data=[]}return N(A,[{key:"add",value:function(A,M,t){var I=this.modals.indexOf(A),g=this.containers.indexOf(M);if(I!==-1)return I;if(I=this.modals.length,this.modals.push(A),this.hideSiblingNodes&&(0,r.hideSiblings)(M,A.mountNode),g!==-1)return this.data[g].modals.push(A),I;var e={modals:[A],classes:t?t.split(/\s+/):[],overflowing:(0,Q.default)(M)};return this.handleContainerOverflow&&T(e,M),e.classes.forEach(c.default.addClass.bind(null,M)),this.containers.push(M),this.data.push(e),I}},{key:"remove",value:function(A){var M=this.modals.indexOf(A);if(M!==-1){var t=i(this.data,A),I=this.data[t],g=this.containers[t];I.modals.splice(I.modals.indexOf(A),1),this.modals.splice(M,1),0===I.modals.length?(I.classes.forEach(c.default.removeClass.bind(null,g)),this.handleContainerOverflow&&E(I,g),this.hideSiblingNodes&&(0,r.showSiblings)(g,A.mountNode),this.containers.splice(t,1),this.data.splice(t,1)):this.hideSiblingNodes&&(0,r.ariaHidden)(!1,I.modals[I.modals.length-1].mountNode)}}},{key:"isTopModal",value:function(A){return!!this.modals.length&&this.modals[this.modals.length-1]===A}}]),A}();M.default=s,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=Object.assign||function(A){for(var M=1;M1?t-1:0),g=1;g=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}function E(){}Object.defineProperty(M,"__esModule",{value:!0}),M.EXITING=M.ENTERED=M.ENTERING=M.EXITED=M.UNMOUNTED=void 0;var N=Object.assign||function(A){for(var M=1;MT?T-N:0}function i(A,M,t,I){var e=g(t),i=e.width,T=A-I,E=A+I+M;return T<0?-T:E>i?i-E:0}function T(A,M,t,I,g){var T="BODY"===I.tagName?(0,N.default)(t):(0,n.default)(t,I),E=(0,N.default)(M),o=E.height,C=E.width,c=void 0,D=void 0,a=void 0,B=void 0;if("left"===A||"right"===A){D=T.top+(T.height-o)/2,c="left"===A?T.left-C:T.left+T.width;var Q=e(D,o,I,g);D+=Q,B=50*(1-2*Q/o)+"%",a=void 0}else{if("top"!==A&&"bottom"!==A)throw new Error('calcOverlayPosition(): No such placement of "'+A+'" found.');c=T.left+(T.width-C)/2,D="top"===A?T.top-o:T.top+T.height;var r=i(c,C,I,g);c+=r,a=50*(1-2*r/C)+"%",B=void 0}return{positionLeft:c,positionTop:D,arrowOffsetLeft:a,arrowOffsetTop:B}}Object.defineProperty(M,"__esModule",{value:!0}),M.default=T;var E=t(143),N=I(E),o=t(287),n=I(o),C=t(144),c=I(C),D=t(52),a=I(D);A.exports=M.default},function(A,M){"use strict";function t(A,M){M&&(A?M.setAttribute("aria-hidden","true"):M.removeAttribute("aria-hidden"))}function I(A,M){T(A,M,function(A){return t(!0,A)})}function g(A,M){T(A,M,function(A){return t(!1,A)})}Object.defineProperty(M,"__esModule",{value:!0}),M.ariaHidden=t,M.hideSiblings=I,M.showSiblings=g;var e=["template","script","style"],i=function(A){var M=A.nodeType,t=A.tagName;return 1===M&&e.indexOf(t.toLowerCase())===-1},T=function(A,M,t){M=[].concat(M),[].forEach.call(A.children,function(A){M.indexOf(A)===-1&&i(A)&&t(A)})}},function(A,M,t){"use strict";var I=function(){};A.exports=I},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){return function(t,I,g){if(null!=t[I]){var e='"'+I+'" property of "'+g+'" has been deprecated.\n'+M;E[e]||(T.default(!1,e),E[e]=!0)}return A(t,I,g)}}function e(){E={}}M.__esModule=!0,M.default=g;var i=t(127),T=I(i),E={};g._resetWarned=e,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function e(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function i(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}M.__esModule=!0,M.default=void 0;var T=t(1),E=t(184),N=I(E),o=t(185),n=(I(o),function(A){function M(t,I){g(this,M);var i=e(this,A.call(this,t,I));return i.store=t.store,i}return i(M,A),M.prototype.getChildContext=function(){return{store:this.store}},M.prototype.render=function(){return T.Children.only(this.props.children)},M}(T.Component));M.default=n,n.propTypes={store:N.default.isRequired,children:T.PropTypes.element.isRequired},n.childContextTypes={store:N.default.isRequired}},function(A,M){"use strict";function t(A,M){if(A===M)return!0;var t=Object.keys(A),I=Object.keys(M);if(t.length!==I.length)return!1;for(var g=Object.prototype.hasOwnProperty,e=0;e=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){var t=A.history,I=A.routes,e=A.location,E=g(A,["history","routes","location"]);t||e?void 0:(0,N.default)(!1),t=t?t:(0,n.default)(E);var o=(0,c.default)(t,(0,D.createRoutes)(I)),C=void 0;e?e=t.createLocation(e):C=t.listen(function(A){e=A});var B=(0,a.createRouterObject)(t,o);t=(0,a.createRoutingHistory)(t,o),o.match(e,function(A,I,g){M(A,I&&B.createLocation(I,T.REPLACE),g&&i({},g,{history:t,router:B,matchContext:{history:t,transitionManager:o,router:B}})),C&&C()})}M.__esModule=!0;var i=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){return function(){var M=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],t=M.routes,I=g(M,["routes"]),e=(0,E.default)(A)(I),T=(0,o.default)(e,t);return i({},e,T)}}M.__esModule=!0;var i=Object.assign||function(A){for(var M=1;M=A&&N&&(T=!0,t()))}}var i=0,T=!1,E=!1,N=!1,o=void 0;e()}M.__esModule=!0;var I=Array.prototype.slice;M.loopAsync=t},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(){function A(A){try{A=A||window.history.state||{}}catch(M){A={}}var M=n.getWindowPath(),t=A,I=t.key,g=void 0;I?g=C.readState(I):(g=null,I=s.createKey(),Q&&window.history.replaceState(e({},A,{key:I}),null));var i=N.parsePath(M);return s.createLocation(e({},i,{state:g}),void 0,I)}function M(M){function t(M){void 0!==M.state&&I(A(M.state))}var I=M.transitionTo;return n.addEventListener(window,"popstate",t),function(){n.removeEventListener(window,"popstate",t)}}function t(A){var M=A.basename,t=A.pathname,I=A.search,g=A.hash,e=A.state,i=A.action,T=A.key;if(i!==E.POP){C.saveState(T,e);var N=(M||"")+t+I+g,o={key:T};if(i===E.PUSH){if(r)return window.location.href=N,!1;window.history.pushState(o,null,N)}else{if(r)return window.location.replace(N),!1;window.history.replaceState(o,null,N)}}}function I(A){1===++x&&(j=M(s));var t=s.listenBefore(A);return function(){t(),0===--x&&j()}}function g(A){1===++x&&(j=M(s));var t=s.listen(A);return function(){t(),0===--x&&j()}}function i(A){1===++x&&(j=M(s)),s.registerTransitionHook(A)}function c(A){s.unregisterTransitionHook(A),0===--x&&j()}var a=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];o.canUseDOM?void 0:T.default(!1);var B=a.forceRefresh,Q=n.supportsHistory(),r=!Q||B,s=D.default(e({},a,{getCurrentLocation:A,finishTransition:t,saveState:C.saveState})),x=0,j=void 0;return e({},s,{listenBefore:I,listen:g,registerTransitionHook:i,unregisterTransitionHook:c})}M.__esModule=!0;var e=Object.assign||function(A){for(var M=1;M=0&&M=0&&B8&&u<=11),l=32,Y=String.fromCharCode(l),d=c.topLevelTypes,h={beforeInput:{phasedRegistrationNames:{bubbled:s({onBeforeInput:null}),captured:s({onBeforeInputCapture:null})},dependencies:[d.topCompositionEnd,d.topKeyPress,d.topTextInput,d.topPaste]},compositionEnd:{phasedRegistrationNames:{bubbled:s({onCompositionEnd:null}),captured:s({onCompositionEndCapture:null})},dependencies:[d.topBlur,d.topCompositionEnd,d.topKeyDown,d.topKeyPress,d.topKeyUp,d.topMouseDown]},compositionStart:{phasedRegistrationNames:{bubbled:s({onCompositionStart:null}),captured:s({onCompositionStartCapture:null})},dependencies:[d.topBlur,d.topCompositionStart,d.topKeyDown,d.topKeyPress,d.topKeyUp,d.topMouseDown]},compositionUpdate:{phasedRegistrationNames:{bubbled:s({onCompositionUpdate:null}),captured:s({onCompositionUpdateCapture:null})},dependencies:[d.topBlur,d.topCompositionUpdate,d.topKeyDown,d.topKeyPress,d.topKeyUp,d.topMouseDown]}},S=!1,z=null,U={eventTypes:h,extractEvents:function(A,M,t,I,g){return[N(A,M,t,I,g),C(A,M,t,I,g)]}};A.exports=U},function(A,M,t){"use strict";var I=t(202),g=t(10),e=t(17),i=(t(297),t(475)),T=t(302),E=t(306),N=(t(3),E(function(A){return T(A)})),o=!1,n="cssFloat";if(g.canUseDOM){var C=document.createElement("div").style;try{C.font=""}catch(A){o=!0}void 0===document.documentElement.style.cssFloat&&(n="styleFloat")}var c={createMarkupForStyles:function(A){var M="";for(var t in A)if(A.hasOwnProperty(t)){var I=A[t];null!=I&&(M+=N(t)+":",M+=i(t,I)+";")}return M||null},setValueForStyles:function(A,M){var t=A.style;for(var g in M)if(M.hasOwnProperty(g)){var e=i(g,M[g]);if("float"===g&&(g=n),e)t[g]=e;else{var T=o&&I.shorthandPropertyExpansions[g];if(T)for(var E in T)t[E]="";else t[g]=""}}}};e.measureMethods(c,"CSSPropertyOperations",{setValueForStyles:"setValueForStyles"}),A.exports=c},function(A,M,t){"use strict";function I(A){var M=A.nodeName&&A.nodeName.toLowerCase();return"select"===M||"input"===M&&"file"===A.type}function g(A){var M=u.getPooled(h.change,z,A,w(A));x.accumulateTwoPhaseDispatches(M),y.batchedUpdates(e,M)}function e(A){s.enqueueEvents(A),s.processEventQueue(!1)}function i(A,M){S=A,z=M,S.attachEvent("onchange",g)}function T(){S&&(S.detachEvent("onchange",g),S=null,z=null)}function E(A,M,t){if(A===d.topChange)return t}function N(A,M,t){A===d.topFocus?(T(),i(M,t)):A===d.topBlur&&T()}function o(A,M){S=A,z=M,U=A.value,p=Object.getOwnPropertyDescriptor(A.constructor.prototype,"value"),Object.defineProperty(S,"value",F),S.attachEvent("onpropertychange",C)}function n(){S&&(delete S.value,S.detachEvent("onpropertychange",C),S=null,z=null,U=null,p=null)}function C(A){if("value"===A.propertyName){var M=A.srcElement.value;M!==U&&(U=M,g(A))}}function c(A,M,t){if(A===d.topInput)return t}function D(A,M,t){A===d.topFocus?(n(),o(M,t)):A===d.topBlur&&n()}function a(A,M,t){if((A===d.topSelectionChange||A===d.topKeyUp||A===d.topKeyDown)&&S&&S.value!==U)return U=S.value,z}function B(A){return A.nodeName&&"input"===A.nodeName.toLowerCase()&&("checkbox"===A.type||"radio"===A.type)}function Q(A,M,t){if(A===d.topClick)return t}var r=t(24),s=t(53),x=t(54),j=t(10),y=t(18),u=t(37),w=t(117),L=t(120),l=t(229),Y=t(27),d=r.topLevelTypes,h={ -change:{phasedRegistrationNames:{bubbled:Y({onChange:null}),captured:Y({onChangeCapture:null})},dependencies:[d.topBlur,d.topChange,d.topClick,d.topFocus,d.topInput,d.topKeyDown,d.topKeyUp,d.topSelectionChange]}},S=null,z=null,U=null,p=null,O=!1;j.canUseDOM&&(O=L("change")&&(!("documentMode"in document)||document.documentMode>8));var m=!1;j.canUseDOM&&(m=L("input")&&(!("documentMode"in document)||document.documentMode>9));var F={get:function(){return p.get.call(this)},set:function(A){U=""+A,p.set.call(this,A)}},f={eventTypes:h,extractEvents:function(A,M,t,g,e){var i,T;if(I(M)?O?i=E:T=N:l(M)?m?i=c:(i=a,T=D):B(M)&&(i=Q),i){var o=i(A,M,t);if(o){var n=u.getPooled(h.change,o,g,e);return n.type="change",x.accumulateTwoPhaseDispatches(n),n}}T&&T(A,M,t)}};A.exports=f},function(A,M){"use strict";var t=0,I={createReactRootIndex:function(){return t++}};A.exports=I},function(A,M,t){"use strict";function I(A){return A.substring(1,A.indexOf(" "))}var g=t(10),e=t(299),i=t(20),T=t(151),E=t(2),N=/^(<[^ \/>]+)/,o="data-danger-index",n={dangerouslyRenderMarkup:function(A){g.canUseDOM?void 0:E(!1);for(var M,t={},n=0;n1?1-M:void 0;return this._fallbackText=g.slice(A,T),this._fallbackText}}),g.addPoolingTo(I),A.exports=I},function(A,M,t){"use strict";var I,g=t(47),e=t(10),i=g.injection.MUST_USE_ATTRIBUTE,T=g.injection.MUST_USE_PROPERTY,E=g.injection.HAS_BOOLEAN_VALUE,N=g.injection.HAS_SIDE_EFFECTS,o=g.injection.HAS_NUMERIC_VALUE,n=g.injection.HAS_POSITIVE_NUMERIC_VALUE,C=g.injection.HAS_OVERLOADED_BOOLEAN_VALUE;if(e.canUseDOM){var c=document.implementation;I=c&&c.hasFeature&&c.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")}var D={isCustomAttribute:RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/),Properties:{accept:null,acceptCharset:null,accessKey:null,action:null,allowFullScreen:i|E,allowTransparency:i,alt:null,async:E,autoComplete:null,autoPlay:E,capture:i|E,cellPadding:null,cellSpacing:null,charSet:i,challenge:i,checked:T|E,classID:i,className:I?i:T,cols:i|n,colSpan:null,content:null,contentEditable:null,contextMenu:i,controls:T|E,coords:null,crossOrigin:null,data:null,dateTime:i,default:E,defer:E,dir:null,disabled:i|E,download:C,draggable:null,encType:null,form:i,formAction:i,formEncType:i,formMethod:i,formNoValidate:E,formTarget:i,frameBorder:i,headers:null,height:i,hidden:i|E,high:null,href:null,hrefLang:null,htmlFor:null,httpEquiv:null,icon:null,id:T,inputMode:i,integrity:null,is:i,keyParams:i,keyType:i,kind:null,label:null,lang:null,list:i,loop:T|E,low:null,manifest:i,marginHeight:null,marginWidth:null,max:null,maxLength:i,media:i,mediaGroup:null,method:null,min:null,minLength:i,multiple:T|E,muted:T|E,name:null,nonce:i,noValidate:E,open:E,optimum:null,pattern:null,placeholder:null,poster:null,preload:null,radioGroup:null,readOnly:T|E,rel:null,required:E,reversed:E,role:i,rows:i|n,rowSpan:null,sandbox:null,scope:null,scoped:E,scrolling:null,seamless:i|E,selected:T|E,shape:null,size:i|n,sizes:i,span:n,spellCheck:null,src:null,srcDoc:T,srcLang:null,srcSet:i,start:o,step:null,style:null,summary:null,tabIndex:null,target:null,title:null,type:null,useMap:null,value:T|N,width:i,wmode:i,wrap:null,about:i,datatype:i,inlist:i,prefix:i,property:i,resource:i,typeof:i,vocab:i,autoCapitalize:i,autoCorrect:i,autoSave:null,color:null,itemProp:i,itemScope:i|E,itemType:i,itemID:i,itemRef:i,results:null,security:i,unselectable:i},DOMAttributeNames:{acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{autoComplete:"autocomplete",autoFocus:"autofocus",autoPlay:"autoplay",autoSave:"autosave",encType:"encoding",hrefLang:"hreflang",radioGroup:"radiogroup",spellCheck:"spellcheck",srcDoc:"srcdoc",srcSet:"srcset"}};A.exports=D},function(A,M,t){"use strict";var I=t(208),g=t(449),e=t(454),i=t(4),T=t(476),E={};i(E,e),i(E,{findDOMNode:T("findDOMNode","ReactDOM","react-dom",I,I.findDOMNode),render:T("render","ReactDOM","react-dom",I,I.render),unmountComponentAtNode:T("unmountComponentAtNode","ReactDOM","react-dom",I,I.unmountComponentAtNode),renderToString:T("renderToString","ReactDOMServer","react-dom/server",g,g.renderToString),renderToStaticMarkup:T("renderToStaticMarkup","ReactDOMServer","react-dom/server",g,g.renderToStaticMarkup)}),E.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=I,E.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=g,A.exports=E},function(A,M,t){"use strict";var I=(t(55),t(114)),g=(t(3),"_getDOMNodeDidWarn"),e={getDOMNode:function(){return this.constructor[g]=!0,I(this)}};A.exports=e},function(A,M,t){"use strict";function I(A,M,t){var I=void 0===A[t];null!=M&&I&&(A[t]=e(M,null))}var g=t(36),e=t(119),i=t(122),T=t(123),E=(t(3),{instantiateChildren:function(A,M,t){if(null==A)return null;var g={};return T(A,I,g),g},updateChildren:function(A,M,t,I){if(!M&&!A)return null;var T;for(T in M)if(M.hasOwnProperty(T)){var E=A&&A[T],N=E&&E._currentElement,o=M[T];if(null!=E&&i(N,o))g.receiveComponent(E,o,t,I),M[T]=E;else{E&&g.unmountComponent(E,T);var n=e(o,null);M[T]=n}}for(T in A)!A.hasOwnProperty(T)||M&&M.hasOwnProperty(T)||g.unmountComponent(A[T]);return M},unmountChildren:function(A){for(var M in A)if(A.hasOwnProperty(M)){var t=A[M];g.unmountComponent(t)}}});A.exports=E},function(A,M,t){"use strict";function I(A){var M=A._currentElement._owner||null;if(M){var t=M.getName();if(t)return" Check the render method of ` + "`" + `"+t+"` + "`" + `."}return""}function g(A){}var e=t(110),i=t(25),T=t(13),E=t(55),N=t(17),o=t(71),n=(t(70),t(36)),C=t(112),c=t(4),D=t(50),a=t(2),B=t(122);t(3);g.prototype.render=function(){var A=E.get(this)._currentElement.type;return A(this.props,this.context,this.updater)};var Q=1,r={construct:function(A){this._currentElement=A,this._rootNodeID=null,this._instance=null,this._pendingElement=null,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._renderedComponent=null,this._context=null,this._mountOrder=0,this._topLevelWrapper=null,this._pendingCallbacks=null},mountComponent:function(A,M,t){this._context=t,this._mountOrder=Q++,this._rootNodeID=A;var I,e,i=this._processProps(this._currentElement.props),N=this._processContext(t),o=this._currentElement.type,c="prototype"in o;c&&(I=new o(i,N,C)),c&&null!==I&&I!==!1&&!T.isValidElement(I)||(e=I,I=new g(o)),I.props=i,I.context=N,I.refs=D,I.updater=C,this._instance=I,E.set(I,this);var B=I.state;void 0===B&&(I.state=B=null),"object"!=typeof B||Array.isArray(B)?a(!1):void 0,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,I.componentWillMount&&(I.componentWillMount(),this._pendingStateQueue&&(I.state=this._processPendingState(I.props,I.context))),void 0===e&&(e=this._renderValidatedComponent()),this._renderedComponent=this._instantiateReactComponent(e);var r=n.mountComponent(this._renderedComponent,A,M,this._processChildContext(t));return I.componentDidMount&&M.getReactMountReady().enqueue(I.componentDidMount,I),r},unmountComponent:function(){var A=this._instance;A.componentWillUnmount&&A.componentWillUnmount(),n.unmountComponent(this._renderedComponent),this._renderedComponent=null,this._instance=null,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._pendingCallbacks=null,this._pendingElement=null,this._context=null,this._rootNodeID=null,this._topLevelWrapper=null,E.remove(A)},_maskContext:function(A){var M=null,t=this._currentElement.type,I=t.contextTypes;if(!I)return D;M={};for(var g in I)M[g]=A[g];return M},_processContext:function(A){var M=this._maskContext(A);return M},_processChildContext:function(A){var M=this._currentElement.type,t=this._instance,I=t.getChildContext&&t.getChildContext();if(I){"object"!=typeof M.childContextTypes?a(!1):void 0;for(var g in I)g in M.childContextTypes?void 0:a(!1);return c({},A,I)}return A},_processProps:function(A){return A},_checkPropTypes:function(A,M,t){var g=this.getName();for(var e in A)if(A.hasOwnProperty(e)){var i;try{"function"!=typeof A[e]?a(!1):void 0,i=A[e](M,e,g,t)}catch(A){i=A}if(i instanceof Error){I(this);t===o.prop}}},receiveComponent:function(A,M,t){var I=this._currentElement,g=this._context;this._pendingElement=null,this.updateComponent(M,I,A,g,t)},performUpdateIfNecessary:function(A){null!=this._pendingElement&&n.receiveComponent(this,this._pendingElement||this._currentElement,A,this._context),(null!==this._pendingStateQueue||this._pendingForceUpdate)&&this.updateComponent(A,this._currentElement,this._currentElement,this._context,this._context)},updateComponent:function(A,M,t,I,g){var e,i=this._instance,T=this._context===g?i.context:this._processContext(g);M===t?e=t.props:(e=this._processProps(t.props),i.componentWillReceiveProps&&i.componentWillReceiveProps(e,T));var E=this._processPendingState(e,T),N=this._pendingForceUpdate||!i.shouldComponentUpdate||i.shouldComponentUpdate(e,E,T);N?(this._pendingForceUpdate=!1,this._performComponentUpdate(t,e,E,T,A,g)):(this._currentElement=t,this._context=g,i.props=e,i.state=E,i.context=T)},_processPendingState:function(A,M){var t=this._instance,I=this._pendingStateQueue,g=this._pendingReplaceState;if(this._pendingReplaceState=!1,this._pendingStateQueue=null,!I)return t.state;if(g&&1===I.length)return I[0];for(var e=c({},g?I[0]:t.state),i=g?1:0;i=0||null!=M.is}function B(A){D(A),this._tag=A.toLowerCase(),this._renderedChildren=null,this._previousStyle=null,this._previousStyleCopy=null,this._rootNodeID=null,this._wrapperState=null,this._topLevelWrapper=null,this._nodeWithLegacyProperties=null}var Q=t(428),r=t(430),s=t(47),x=t(107),j=t(24),y=t(69),u=t(109),w=t(443),L=t(446),l=t(447),Y=t(210),d=t(450),h=t(12),S=t(455),z=t(17),U=t(112),p=t(4),O=t(74),m=t(75),F=t(2),f=(t(120),t(27)),k=t(76),R=t(121),J=(t(152),t(124),t(3),y.deleteListener),G=y.listenTo,H=y.registrationNameModules,b={string:!0,number:!0},X=f({children:null}),v=f({style:null}),W=f({__html:null}),V=1,P={topAbort:"abort",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topSeeked:"seeked",topSeeking:"seeking",topStalled:"stalled",topSuspend:"suspend",topTimeUpdate:"timeupdate",topVolumeChange:"volumechange",topWaiting:"waiting"},Z={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},K={listing:!0,pre:!0,textarea:!0},q=(p({menuitem:!0},Z),/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/),_={},$={}.hasOwnProperty;B.displayName="ReactDOMComponent",B.Mixin={construct:function(A){this._currentElement=A},mountComponent:function(A,M,t){this._rootNodeID=A;var I=this._currentElement.props;switch(this._tag){case"iframe":case"img":case"form":case"video":case"audio":this._wrapperState={listeners:null},M.getReactMountReady().enqueue(n,this);break;case"button":I=w.getNativeProps(this,I,t);break;case"input":L.mountWrapper(this,I,t),I=L.getNativeProps(this,I,t);break;case"option":l.mountWrapper(this,I,t),I=l.getNativeProps(this,I,t);break;case"select":Y.mountWrapper(this,I,t),I=Y.getNativeProps(this,I,t),t=Y.processChildContext(this,I,t);break;case"textarea":d.mountWrapper(this,I,t),I=d.getNativeProps(this,I,t)}E(this,I);var g;if(M.useCreateElement){var e=t[h.ownerDocumentContextKey],i=e.createElement(this._currentElement.type);x.setAttributeForID(i,this._rootNodeID),h.getID(i),this._updateDOMProperties({},I,M,i),this._createInitialChildren(M,I,t,i),g=i}else{var T=this._createOpenTagMarkupAndPutListeners(M,I),N=this._createContentMarkup(M,I,t);g=!N&&Z[this._tag]?T+"/>":T+">"+N+""}switch(this._tag){case"input":M.getReactMountReady().enqueue(C,this);case"button":case"select":case"textarea":I.autoFocus&&M.getReactMountReady().enqueue(Q.focusDOMComponent,this)}return g},_createOpenTagMarkupAndPutListeners:function(A,M){var t="<"+this._currentElement.type;for(var I in M)if(M.hasOwnProperty(I)){var g=M[I];if(null!=g)if(H.hasOwnProperty(I))g&&N(this._rootNodeID,I,g,A);else{I===v&&(g&&(g=this._previousStyleCopy=p({},M.style)),g=r.createMarkupForStyles(g));var e=null;null!=this._tag&&a(this._tag,M)?I!==X&&(e=x.createMarkupForCustomAttribute(I,g)):e=x.createMarkupForProperty(I,g),e&&(t+=" "+e)}}if(A.renderToStaticMarkup)return t;var i=x.createMarkupForID(this._rootNodeID);return t+" "+i},_createContentMarkup:function(A,M,t){var I="",g=M.dangerouslySetInnerHTML;if(null!=g)null!=g.__html&&(I=g.__html);else{var e=b[typeof M.children]?M.children:null,i=null!=e?null:M.children;if(null!=e)I=m(e);else if(null!=i){var T=this.mountChildren(i,A,t);I=T.join("")}}return K[this._tag]&&"\n"===I.charAt(0)?"\n"+I:I},_createInitialChildren:function(A,M,t,I){var g=M.dangerouslySetInnerHTML;if(null!=g)null!=g.__html&&k(I,g.__html);else{var e=b[typeof M.children]?M.children:null,i=null!=e?null:M.children;if(null!=e)R(I,e);else if(null!=i)for(var T=this.mountChildren(i,A,t),E=0;EM.end?(t=M.end,I=M.start):(t=M.start,I=M.end),g.moveToElementText(A),g.moveStart("character",t),g.setEndPoint("EndToStart",g),g.moveEnd("character",I-t),g.select()}function T(A,M){if(window.getSelection){var t=window.getSelection(),I=A[o()].length,g=Math.min(M.start,I),e="undefined"==typeof M.end?g:Math.min(M.end,I);if(!t.extend&&g>e){var i=e;e=g,g=i}var T=N(A,g),E=N(A,e);if(T&&E){var n=document.createRange();n.setStart(T.node,T.offset),t.removeAllRanges(),g>e?(t.addRange(n),t.extend(E.node,E.offset)):(n.setEnd(E.node,E.offset),t.addRange(n))}}}var E=t(10),N=t(479),o=t(228),n=E.canUseDOM&&"selection"in document&&!("getSelection"in window),C={getOffsets:n?g:e,setOffsets:n?i:T};A.exports=C},function(A,M,t){"use strict";var I=t(213),g=t(460),e=t(113);I.inject();var i={renderToString:g.renderToString,renderToStaticMarkup:g.renderToStaticMarkup,version:e};A.exports=i},function(A,M,t){"use strict";function I(){this._rootNodeID&&o.updateWrapper(this)}function g(A){var M=this._currentElement.props,t=e.executeOnChange(M,A);return T.asap(I,this),t}var e=t(108),i=t(111),T=t(18),E=t(4),N=t(2),o=(t(3),{getNativeProps:function(A,M,t){null!=M.dangerouslySetInnerHTML?N(!1):void 0;var I=E({},M,{defaultValue:void 0,value:void 0,children:A._wrapperState.initialValue,onChange:A._wrapperState.onChange});return I},mountWrapper:function(A,M){var t=M.defaultValue,I=M.children;null!=I&&(null!=t?N(!1):void 0,Array.isArray(I)&&(I.length<=1?void 0:N(!1),I=I[0]),t=""+I),null==t&&(t="");var i=e.getValue(M);A._wrapperState={initialValue:""+(null!=i?i:t),onChange:g.bind(A)}},updateWrapper:function(A){var M=A._currentElement.props,t=e.getValue(M);null!=t&&i.updatePropertyByID(A._rootNodeID,"value",""+t)}});A.exports=o},function(A,M,t){"use strict";function I(A){g.enqueueEvents(A),g.processEventQueue(!1)}var g=t(53),e={handleTopLevel:function(A,M,t,e,i){var T=g.extractEvents(A,M,t,e,i);I(T)}};A.exports=e},function(A,M,t){"use strict";function I(A){var M=C.getID(A),t=n.getReactRootIDFromNodeID(M),I=C.findReactContainerForID(t),g=C.getFirstReactDOM(I);return g}function g(A,M){this.topLevelType=A,this.nativeEvent=M,this.ancestors=[]}function e(A){i(A)}function i(A){for(var M=C.getFirstReactDOM(a(A.nativeEvent))||window,t=M;t;)A.ancestors.push(t),t=I(t);for(var g=0;g=M)return{node:g,offset:M-e};e=i}g=t(I(g))}}A.exports=g},function(A,M,t){"use strict";function I(A){return g.isValidElement(A)?void 0:e(!1),A}var g=t(13),e=t(2);A.exports=I},function(A,M,t){"use strict";function I(A){return'"'+g(A)+'"'}var g=t(75);A.exports=I},function(A,M,t){"use strict";var I=t(12);A.exports=I.renderSubtreeIntoContainer},function(A,M){A.exports=function(A,M,t){for(var I=0,g=A.length,e=3==arguments.length?t:A[I++];I=400){var T="cannot "+M.method+" "+M.url+" ("+i.status+")";A=new e(T),A.status=i.status,A.body=i.body,A.res=i,I(A)}else g?I(new e(g)):t(i)})})},g.prototype.then=function(){var A=this.promise();return A.then.apply(A,arguments)}},function(A,M,t){function I(){}function g(A){var M={}.toString.call(A);switch(M){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function e(A){if(!s(A))return A;var M=[];for(var t in A)null!=A[t]&&i(M,t,A[t]);return M.join("&")}function i(A,M,t){return Array.isArray(t)?t.forEach(function(t){i(A,M,t)}):void A.push(encodeURIComponent(M)+"="+encodeURIComponent(t))}function T(A){for(var M,t,I={},g=A.split("&"),e=0,i=g.length;e=200&&M.status<300)return t.callback(A,M);var I=new Error(M.statusText||"Unsuccessful HTTP response");I.original=A,I.response=M,I.status=M.status,t.callback(I,M)})}function D(A,M){var t=x("DELETE",A);return M&&t.end(M),t}var a,B=t(273),Q=t(483),r=t(501),s=t(236);a="undefined"!=typeof window?window:"undefined"!=typeof self?self:this;var x=A.exports=t(502).bind(null,c);x.getXHR=function(){if(!(!a.XMLHttpRequest||a.location&&"file:"==a.location.protocol&&a.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(A){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(A){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(A){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(A){}return!1};var j="".trim?function(A){return A.trim()}:function(A){return A.replace(/(^\s*|\s*$)/g,"")};x.serializeObject=e,x.parseString=T,x.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},x.serialize={"application/x-www-form-urlencoded":e,"application/json":JSON.stringify},x.parse={"application/x-www-form-urlencoded":T,"application/json":JSON.parse},C.prototype.get=function(A){return this.header[A.toLowerCase()]},C.prototype.setHeaderProperties=function(A){var M=this.header["content-type"]||"";this.type=o(M);var t=n(M);for(var I in t)this[I]=t[I]},C.prototype.parseBody=function(A){ -var M=x.parse[this.type];return!M&&N(this.type)&&(M=x.parse["application/json"]),M&&A&&(A.length||A instanceof Object)?M(A):null},C.prototype.setStatusProperties=function(A){1223===A&&(A=204);var M=A/100|0;this.status=this.statusCode=A,this.statusType=M,this.info=1==M,this.ok=2==M,this.clientError=4==M,this.serverError=5==M,this.error=(4==M||5==M)&&this.toError(),this.accepted=202==A,this.noContent=204==A,this.badRequest=400==A,this.unauthorized=401==A,this.notAcceptable=406==A,this.notFound=404==A,this.forbidden=403==A},C.prototype.toError=function(){var A=this.req,M=A.method,t=A.url,I="cannot "+M+" "+t+" ("+this.status+")",g=new Error(I);return g.status=this.status,g.method=M,g.url=t,g},x.Response=C,B(c.prototype);for(var y in r)c.prototype[y]=r[y];c.prototype.abort=function(){if(!this.aborted)return this.aborted=!0,this.xhr&&this.xhr.abort(),this.clearTimeout(),this.emit("abort"),this},c.prototype.type=function(A){return this.set("Content-Type",x.types[A]||A),this},c.prototype.responseType=function(A){return this._responseType=A,this},c.prototype.accept=function(A){return this.set("Accept",x.types[A]||A),this},c.prototype.auth=function(A,M,t){switch(t||(t={type:"basic"}),t.type){case"basic":var I=btoa(A+":"+M);this.set("Authorization","Basic "+I);break;case"auto":this.username=A,this.password=M}return this},c.prototype.query=function(A){return"string"!=typeof A&&(A=e(A)),A&&this._query.push(A),this},c.prototype.attach=function(A,M,t){return this._getFormData().append(A,M,t||M.name),this},c.prototype._getFormData=function(){return this._formData||(this._formData=new a.FormData),this._formData},c.prototype.send=function(A){var M=s(A),t=this._header["content-type"];if(M&&s(this._data))for(var I in A)this._data[I]=A[I];else"string"==typeof A?(t||this.type("form"),t=this._header["content-type"],"application/x-www-form-urlencoded"==t?this._data=this._data?this._data+"&"+A:A:this._data=(this._data||"")+A):this._data=A;return!M||g(A)?this:(t||this.type("json"),this)},C.prototype.parse=function(A){return a.console&&console.warn("Client-side parse() method has been renamed to serialize(). This method is not compatible with superagent v2.0"),this.serialize(A),this},C.prototype.serialize=function(A){return this._parser=A,this},c.prototype.callback=function(A,M){var t=this._callback;this.clearTimeout(),t(A,M)},c.prototype.crossDomainError=function(){var A=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");A.crossDomain=!0,A.status=this.status,A.method=this.method,A.url=this.url,this.callback(A)},c.prototype.timeoutError=function(){var A=this._timeout,M=new Error("timeout of "+A+"ms exceeded");M.timeout=A,this.callback(M)},c.prototype.withCredentials=function(){return this._withCredentials=!0,this},c.prototype.end=function(A){var M=this,t=this.xhr=x.getXHR(),e=this._query.join("&"),i=this._timeout,T=this._formData||this._data;this._callback=A||I,t.onreadystatechange=function(){if(4==t.readyState){var A;try{A=t.status}catch(M){A=0}if(0==A){if(M.timedout)return M.timeoutError();if(M.aborted)return;return M.crossDomainError()}M.emit("end")}};var E=function(A){A.total>0&&(A.percent=A.loaded/A.total*100),A.direction="download",M.emit("progress",A)};this.hasListeners("progress")&&(t.onprogress=E);try{t.upload&&this.hasListeners("progress")&&(t.upload.onprogress=E)}catch(A){}if(i&&!this._timer&&(this._timer=setTimeout(function(){M.timedout=!0,M.abort()},i)),e&&(e=x.serializeObject(e),this.url+=~this.url.indexOf("?")?"&"+e:"?"+e),this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0),this._withCredentials&&(t.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof T&&!g(T)){var o=this._header["content-type"],n=this._parser||x.serialize[o?o.split(";")[0]:""];!n&&N(o)&&(n=x.serialize["application/json"]),n&&(T=n(T))}for(var C in this.header)null!=this.header[C]&&t.setRequestHeader(C,this.header[C]);return this._responseType&&(t.responseType=this._responseType),this.emit("request",this),t.send("undefined"!=typeof T?T:null),this},x.Request=c,x.get=function(A,M,t){var I=x("GET",A);return"function"==typeof M&&(t=M,M=null),M&&I.query(M),t&&I.end(t),I},x.head=function(A,M,t){var I=x("HEAD",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I},x.del=D,x.delete=D,x.patch=function(A,M,t){var I=x("PATCH",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I},x.post=function(A,M,t){var I=x("POST",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I},x.put=function(A,M,t){var I=x("PUT",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I}},function(A,M,t){var I=t(236);M.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},M.parse=function(A){return this._parser=A,this},M.timeout=function(A){return this._timeout=A,this},M.then=function(A,M){return this.end(function(t,I){t?M(t):A(I)})},M.use=function(A){return A(this),this},M.get=function(A){return this._header[A.toLowerCase()]},M.getHeader=M.get,M.set=function(A,M){if(I(A)){for(var t in A)this.set(t,A[t]);return this}return this._header[A.toLowerCase()]=M,this.header[A]=M,this},M.unset=function(A){return delete this._header[A.toLowerCase()],delete this.header[A],this},M.field=function(A,M){return this._getFormData().append(A,M),this}},function(A,M){function t(A,M,t){return"function"==typeof t?new A("GET",M).end(t):2==arguments.length?new A("GET",M):new A(M,t)}A.exports=t},function(A,M,t){A.exports=t(504)},function(A,M,t){(function(A,I){"use strict";function g(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var e,i=t(505),T=g(i);e="undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof A?A:I;var E=(0,T.default)(e);M.default=E}).call(M,function(){return this}(),t(128)(A))},function(A,M){"use strict";function t(A){var M,t=A.Symbol;return"function"==typeof t?t.observable?M=t.observable:(M=t("observable"),t.observable=M):M="@@observable",M}Object.defineProperty(M,"__esModule",{value:!0}),M.default=t},function(A,M,t){function I(A){return g(A).replace(/\s(\w)/g,function(A,M){return M.toUpperCase()})}var g=t(508);A.exports=I},function(A,M){function t(A){return e.test(A)?A.toLowerCase():i.test(A)?(I(A)||A).toLowerCase():T.test(A)?g(A).toLowerCase():A.toLowerCase()}function I(A){return A.replace(E,function(A,M){return M?" "+M:""})}function g(A){return A.replace(N,function(A,M,t){return M+" "+t.toLowerCase().split("").join(" ")})}A.exports=t;var e=/\s/,i=/(_|-|\.|:)/,T=/([a-z][A-Z]|[A-Z][a-z])/,E=/[\W_]+(.|$)/g,N=/(.)([A-Z]+)/g},function(A,M,t){function I(A){return g(A).replace(/[\W_]+(.|$)/g,function(A,M){return M?" "+M:""}).trim()}var g=t(507);A.exports=I},function(A,M){A.exports=function(){var A=document.getSelection();if(!A.rangeCount)return function(){};for(var M=document.activeElement,t=[],I=0;I=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function i(A,M){function t(I,g){function i(A,t){var I=c.getLinkName(A),e=this.props[g[A]];I&&E(this.props,I)&&!e&&(e=this.props[I].requestChange);for(var i=arguments.length,T=Array(i>2?i-2:0),N=2;N=15||0===s[0]&&s[1]>=13?A:A.type}function T(A,M){var t=N(M);return t&&!E(A,M)&&E(A,t)?A[t].value:A[M]}function E(A,M){return void 0!==A[M]}function N(A){return"value"===A?"valueLink":"checked"===A?"checkedLink":null}function o(A){return"default"+A.charAt(0).toUpperCase()+A.substr(1)}function n(A,M,t){return function(){for(var I=arguments.length,g=Array(I),e=0;eo||N===o&&"application/"===M[T].substr(0,12))continue}M[T]=I}}})}var E=t(351),N=t(354).extname,o=/^\s*([^;\s]*)(?:;|\s|$)/,n=/^text\//i;M.charset=I,M.charsets={lookup:I},M.contentType=g,M.extension=e,M.extensions=Object.create(null),M.lookup=i,M.types=Object.create(null),T(M.extensions,M.types)},function(A,M){function t(A){throw new Error("Cannot find module '"+A+"'.")}t.keys=function(){return[]},t.resolve=t,A.exports=t,t.id=353},function(A,M,t){(function(A){function t(A,M){for(var t=0,I=A.length-1;I>=0;I--){var g=A[I];"."===g?A.splice(I,1):".."===g?(A.splice(I,1),t++):t&&(A.splice(I,1),t--)}if(M)for(;t--;t)A.unshift("..");return A}function I(A,M){if(A.filter)return A.filter(M);for(var t=[],I=0;I=-1&&!g;e--){var i=e>=0?arguments[e]:A.cwd();if("string"!=typeof i)throw new TypeError("Arguments to path.resolve must be strings");i&&(M=i+"/"+M,g="/"===i.charAt(0))}return M=t(I(M.split("/"),function(A){return!!A}),!g).join("/"),(g?"/":"")+M||"."},M.normalize=function(A){var g=M.isAbsolute(A),e="/"===i(A,-1);return A=t(I(A.split("/"),function(A){return!!A}),!g).join("/"),A||g||(A="."),A&&e&&(A+="/"),(g?"/":"")+A},M.isAbsolute=function(A){return"/"===A.charAt(0)},M.join=function(){var A=Array.prototype.slice.call(arguments,0);return M.normalize(I(A,function(A,M){if("string"!=typeof A)throw new TypeError("Arguments to path.join must be strings");return A}).join("/"))},M.relative=function(A,t){function I(A){for(var M=0;M=0&&""===A[t];t--);return M>t?[]:A.slice(M,t-M+1)}A=M.resolve(A).substr(1),t=M.resolve(t).substr(1);for(var g=I(A.split("/")),e=I(t.split("/")),i=Math.min(g.length,e.length),T=i,E=0;E=0;e--){var i=I[e]+g;if(i in M)return i}return!1}},function(A,M,t){"use strict";var I=t(497);M.extract=function(A){return A.split("?")[1]||""},M.parse=function(A){return"string"!=typeof A?{}:(A=A.trim().replace(/^(\?|#|&)/,""),A?A.split("&").reduce(function(A,M){var t=M.replace(/\+/g," ").split("="),I=t.shift(),g=t.length>0?t.join("="):void 0;return I=decodeURIComponent(I),g=void 0===g?null:decodeURIComponent(g),A.hasOwnProperty(I)?Array.isArray(A[I])?A[I].push(g):A[I]=[A[I],g]:A[I]=g,A},{}):{})},M.stringify=function(A){return A?Object.keys(A).sort().map(function(M){var t=A[M];return void 0===t?"":null===t?M:Array.isArray(t)?t.slice().sort().map(function(A){return I(M)+"="+I(A)}).join("&"):I(M)+"="+I(t)}).filter(function(A){return A.length>0}).join("&"):""}},function(A,M){"use strict";function t(A,M){return Object.prototype.hasOwnProperty.call(A,M)}A.exports=function(A,M,I,g){M=M||"&",I=I||"=";var e={};if("string"!=typeof A||0===A.length)return e;var i=/\+/g;A=A.split(M);var T=1e3;g&&"number"==typeof g.maxKeys&&(T=g.maxKeys);var E=A.length;T>0&&E>T&&(E=T);for(var N=0;N=0?(o=D.substr(0,a),n=D.substr(a+1)):(o=D,n=""),C=decodeURIComponent(o),c=decodeURIComponent(n),t(e,C)?Array.isArray(e[C])?e[C].push(c):e[C]=[e[C],c]:e[C]=c}return e}},function(A,M){"use strict";var t=function(A){switch(typeof A){case"string":return A;case"boolean":return A?"true":"false";case"number":return isFinite(A)?A:"";default:return""}};A.exports=function(A,M,I,g){return M=M||"&",I=I||"=",null===A&&(A=void 0),"object"==typeof A?Object.keys(A).map(function(g){var e=encodeURIComponent(t(g))+I;return Array.isArray(A[g])?A[g].map(function(A){return e+encodeURIComponent(t(A))}).join(M):e+encodeURIComponent(t(A[g]))}).join(M):g?encodeURIComponent(t(g))+I+encodeURIComponent(t(A)):""}},function(A,M,t){"use strict";M.decode=M.parse=t(358),M.encode=M.stringify=t(359)},function(A,M,t){(function(M){for(var I=t(355),g="undefined"==typeof window?M:window,e=["moz","webkit"],i="AnimationFrame",T=g["request"+i],E=g["cancel"+i]||g["cancelRequest"+i],N=0;!T&&N1)||(e=A,!1)}),e)return new Error("(children) "+I+" - Duplicate children detected of bsRole: "+e+". Only one child each allowed with the following bsRoles: "+M.join(", "))})}},A.exports=M.default},function(A,M,t){"use strict";function I(A){var M=[];return void 0===A?M:(i.default.forEach(A,function(A){M.push(A)}),M)}var g=t(6).default;M.__esModule=!0,M.default=I;var e=t(51),i=g(e);A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}Object.defineProperty(M,"__esModule",{value:!0}),M.CopyToClipboard=void 0;var e=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){var M=A.style,t=g(A,["style"]),I=o({},M,{height:6,right:2,bottom:2,left:2,borderRadius:3});return C.default.createElement("div",o({style:I},t))}function i(A){var M=A.style,t=g(A,["style"]),I=o({},M,{width:6,right:2,bottom:2,top:2,borderRadius:3});return C.default.createElement("div",o({style:I},t))}function T(A){var M=A.style,t=g(A,["style"]),I=o({},M,{cursor:"pointer",borderRadius:"inherit",backgroundColor:"rgba(0,0,0,.2)"});return C.default.createElement("div",o({style:I},t))}function E(A){var M=A.style,t=g(A,["style"]),I=o({},M,{cursor:"pointer",borderRadius:"inherit",backgroundColor:"rgba(0,0,0,.2)"});return C.default.createElement("div",o({style:I},t))}function N(A){return C.default.createElement("div",A)}var o=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}var e=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=Object.assign||function(A){for(var M=1;M0||(this.setState({isDragActive:!1,isDragReject:!1}),this.props.onDragLeave&&this.props.onDragLeave.call(this,A))}},{key:"onDrop",value:function A(M){var t=this,I=this.props,A=I.onDrop,g=I.onDropAccepted,e=I.onDropRejected,i=I.multiple,T=I.disablePreview,E=(0,a.default)(M,i),N=[],o=[];M.preventDefault(),this.enterCounter=0,this.isFileDialogActive=!1,E.forEach(function(A){T||(A.preview=window.URL.createObjectURL(A)),t.fileAccepted(A)&&t.fileMatchSize(A)?N.push(A):o.push(A)}),A&&A.call(this,N,o,M),o.length>0&&e&&e.call(this,o,M),N.length>0&&g&&g.call(this,N,M),this.setState({isDragActive:!1,isDragReject:!1})}},{key:"onClick",value:function A(M){M.stopPropagation();var t=this.props,A=t.onClick,I=t.disableClick;I||(this.open(),A&&A.call(this,M))}},{key:"onFileDialogCancel",value:function A(){var A=this.props.onFileDialogCancel,M=this.fileInputEl,t=this.isFileDialogActive;A&&t&&setTimeout(function(){var I=M.files;I.length||(t=!1,A())},300)}},{key:"fileAccepted",value:function(A){return(0,c.default)(A,this.props.accept)}},{key:"fileMatchSize",value:function(A){return A.size<=this.props.maxSize&&A.size>=this.props.minSize}},{key:"allFilesAccepted",value:function(A){return A.every(this.fileAccepted)}},{key:"open",value:function(){this.isFileDialogActive=!0,this.fileInputEl.value=null,this.fileInputEl.click()}},{key:"render",value:function(){var A=this,M=this.props,t=M.accept,I=M.activeClassName,e=M.inputProps,i=M.multiple,T=M.name,N=M.rejectClassName,o=g(M,["accept","activeClassName","inputProps","multiple","name","rejectClassName"]),C=o.activeStyle,c=o.className,D=o.rejectStyle,a=o.style,Q=g(o,["activeStyle","className","rejectStyle","style"]),r=this.state,s=r.isDragActive,x=r.isDragReject;c=c||"",s&&I&&(c+=" "+I),x&&N&&(c+=" "+N),c||a||C||D||(a={width:200,height:200,borderWidth:2,borderColor:"#666",borderStyle:"dashed",borderRadius:5},C={borderStyle:"solid",backgroundColor:"#eee"},D={borderStyle:"solid",backgroundColor:"#ffdddd"});var j=void 0;j=C&&s?E({},a,C):D&&x?E({},a,D):E({},a);var y={accept:t,type:"file",style:{display:"none"},multiple:B&&i,ref:function(M){return A.fileInputEl=M},onChange:this.onDrop};T&&T.length&&(y.name=T);var u=["acceptedFiles","disablePreview","disableClick","onDropAccepted","onDropRejected","onFileDialogCancel","maxSize","minSize"],w=E({},Q);return u.forEach(function(A){return delete w[A]}),n.default.createElement("div",E({className:c,style:j},w,{onClick:this.onClick,onDragStart:this.onDragStart,onDragEnter:this.onDragEnter,onDragOver:this.onDragOver,onDragLeave:this.onDragLeave,onDrop:this.onDrop}),this.props.children,n.default.createElement("input",E({},e,y)))}}]),M}(n.default.Component);Q.defaultProps={disablePreview:!1,disableClick:!1,multiple:!0,maxSize:1/0,minSize:0},Q.propTypes={onClick:n.default.PropTypes.func,onDrop:n.default.PropTypes.func,onDropAccepted:n.default.PropTypes.func,onDropRejected:n.default.PropTypes.func,onDragStart:n.default.PropTypes.func,onDragEnter:n.default.PropTypes.func,onDragOver:n.default.PropTypes.func,onDragLeave:n.default.PropTypes.func,children:n.default.PropTypes.node,style:n.default.PropTypes.object,activeStyle:n.default.PropTypes.object,rejectStyle:n.default.PropTypes.object,className:n.default.PropTypes.string,activeClassName:n.default.PropTypes.string,rejectClassName:n.default.PropTypes.string,disablePreview:n.default.PropTypes.bool,disableClick:n.default.PropTypes.bool,onFileDialogCancel:n.default.PropTypes.func,inputProps:n.default.PropTypes.object,multiple:n.default.PropTypes.bool,accept:n.default.PropTypes.string,name:n.default.PropTypes.string,maxSize:n.default.PropTypes.number,minSize:n.default.PropTypes.number},M.default=Q,A.exports=M.default},function(M,t){M.exports=A},function(A,M){A.exports=function(A){function M(I){if(t[I])return t[I].exports;var g=t[I]={exports:{},id:I,loaded:!1};return A[I].call(g.exports,g,g.exports,M),g.loaded=!0,g.exports}var t={};return M.m=A,M.c=t,M.p="",M(0)}([function(A,M,t){"use strict";M.__esModule=!0,t(8),t(9),M.default=function(A,M){if(A&&M){var t=function(){var t=Array.isArray(M)?M:M.split(","),I=A.name||"",g=A.type||"",e=g.replace(/\/.*$/,"");return{v:t.some(function(A){var M=A.trim();return"."===M.charAt(0)?I.toLowerCase().endsWith(M.toLowerCase()):/\/\*$/.test(M)?e===M.replace(/\/.*$/,""):g===M})}}();if("object"==typeof t)return t.v}return!0},A.exports=M.default},function(A,M){var t=A.exports={version:"1.2.2"};"number"==typeof __e&&(__e=t)},function(A,M){var t=A.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=t)},function(A,M,t){var I=t(2),g=t(1),e=t(4),i=t(19),T="prototype",E=function(A,M){return function(){return A.apply(M,arguments)}},N=function(A,M,t){var o,n,C,c,D=A&N.G,a=A&N.P,B=D?I:A&N.S?I[M]||(I[M]={}):(I[M]||{})[T],Q=D?g:g[M]||(g[M]={});D&&(t=M);for(o in t)n=!(A&N.F)&&B&&o in B,C=(n?B:t)[o],c=A&N.B&&n?E(C,I):a&&"function"==typeof C?E(Function.call,C):C,B&&!n&&i(B,o,C),Q[o]!=C&&e(Q,o,c),a&&((Q[T]||(Q[T]={}))[o]=C)};I.core=g,N.F=1,N.G=2,N.S=4,N.P=8,N.B=16,N.W=32,A.exports=N},function(A,M,t){var I=t(5),g=t(18);A.exports=t(22)?function(A,M,t){return I.setDesc(A,M,g(1,t))}:function(A,M,t){return A[M]=t,A}},function(A,M){var t=Object;A.exports={create:t.create,getProto:t.getPrototypeOf,isEnum:{}.propertyIsEnumerable,getDesc:t.getOwnPropertyDescriptor,setDesc:t.defineProperty,setDescs:t.defineProperties,getKeys:t.keys,getNames:t.getOwnPropertyNames,getSymbols:t.getOwnPropertySymbols,each:[].forEach}},function(A,M){var t=0,I=Math.random();A.exports=function(A){return"Symbol(".concat(void 0===A?"":A,")_",(++t+I).toString(36))}},function(A,M,t){var I=t(20)("wks"),g=t(2).Symbol;A.exports=function(A){return I[A]||(I[A]=g&&g[A]||(g||t(6))("Symbol."+A))}},function(A,M,t){t(26),A.exports=t(1).Array.some},function(A,M,t){t(25),A.exports=t(1).String.endsWith},function(A,M){A.exports=function(A){if("function"!=typeof A)throw TypeError(A+" is not a function!");return A}},function(A,M){var t={}.toString;A.exports=function(A){return t.call(A).slice(8,-1)}},function(A,M,t){var I=t(10);A.exports=function(A,M,t){if(I(A),void 0===M)return A;switch(t){case 1:return function(t){return A.call(M,t)};case 2:return function(t,I){return A.call(M,t,I)};case 3:return function(t,I,g){return A.call(M,t,I,g)}}return function(){return A.apply(M,arguments)}}},function(A,M){A.exports=function(A){if(void 0==A)throw TypeError("Can't call method on "+A);return A}},function(A,M,t){A.exports=function(A){var M=/./;try{"/./"[A](M)}catch(I){try{return M[t(7)("match")]=!1,!"/./"[A](M)}catch(A){}}return!0}},function(A,M){A.exports=function(A){try{return!!A()}catch(A){return!0}}},function(A,M){A.exports=function(A){return"object"==typeof A?null!==A:"function"==typeof A}},function(A,M,t){var I=t(16),g=t(11),e=t(7)("match");A.exports=function(A){var M;return I(A)&&(void 0!==(M=A[e])?!!M:"RegExp"==g(A))}},function(A,M){A.exports=function(A,M){return{enumerable:!(1&A),configurable:!(2&A),writable:!(4&A),value:M}}},function(A,M,t){var I=t(2),g=t(4),e=t(6)("src"),i="toString",T=Function[i],E=(""+T).split(i);t(1).inspectSource=function(A){return T.call(A)},(A.exports=function(A,M,t,i){"function"==typeof t&&(g(t,e,A[M]?""+A[M]:E.join(String(M))),"name"in t||(t.name=M)),A===I?A[M]=t:(i||delete A[M],g(A,M,t))})(Function.prototype,i,function(){return"function"==typeof this&&this[e]||T.call(this)})},function(A,M,t){var I=t(2),g="__core-js_shared__",e=I[g]||(I[g]={});A.exports=function(A){return e[A]||(e[A]={})}},function(A,M,t){var I=t(17),g=t(13);A.exports=function(A,M,t){if(I(M))throw TypeError("String#"+t+" doesn't accept regex!");return String(g(A))}},function(A,M,t){A.exports=!t(15)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(A,M){var t=Math.ceil,I=Math.floor;A.exports=function(A){return isNaN(A=+A)?0:(A>0?I:t)(A)}},function(A,M,t){var I=t(23),g=Math.min;A.exports=function(A){return A>0?g(I(A),9007199254740991):0}},function(A,M,t){"use strict";var I=t(3),g=t(24),e=t(21),i="endsWith",T=""[i];I(I.P+I.F*t(14)(i),"String",{endsWith:function(A){var M=e(this,A,i),t=arguments,I=t.length>1?t[1]:void 0,E=g(M.length),N=void 0===I?E:Math.min(g(I),E),o=String(A);return T?T.call(M,o,N):M.slice(N-o.length,N)===o}})},function(A,M,t){var I=t(5),g=t(3),e=t(1).Array||Array,i={},T=function(A,M){I.each.call(A.split(","),function(A){void 0==M&&A in e?i[A]=e[A]:A in[]&&(i[A]=t(12)(Function.call,[][A],M))})};T("pop,reverse,shift,keys,values,entries",1),T("indexOf,every,some,forEach,map,filter,find,findIndex,includes",3),T("join,slice,concat,push,splice,unshift,sort,lastIndexOf,reduce,reduceRight,copyWithin,fill"),g(g.S,"Array",i)}])},function(A,M){"use strict";function t(A){var M=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],t=[];if(A.dataTransfer){var I=A.dataTransfer;I.files&&I.files.length?t=I.files:I.items&&I.items.length&&(t=I.items)}else A.target&&A.target.files&&(t=A.target.files);return t.length>0&&(t=M?t:[t[0]]),Array.prototype.slice.call(t)}Object.defineProperty(M,"__esModule",{value:!0}),M.default=t,A.exports=M.default}])})},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=function(){function A(A,M){for(var t=0;t0&&void 0!==arguments[0]?arguments[0]:{},t=M.hideSiblingNodes,I=void 0===t||t,e=M.handleContainerOverflow,i=void 0===e||e;g(this,A),this.hideSiblingNodes=I,this.handleContainerOverflow=i,this.modals=[],this.containers=[],this.data=[]}return N(A,[{key:"add",value:function(A,M,t){var I=this.modals.indexOf(A),g=this.containers.indexOf(M);if(I!==-1)return I;if(I=this.modals.length,this.modals.push(A),this.hideSiblingNodes&&(0,r.hideSiblings)(M,A.mountNode),g!==-1)return this.data[g].modals.push(A),I;var e={modals:[A],classes:t?t.split(/\s+/):[],overflowing:(0,Q.default)(M)};return this.handleContainerOverflow&&T(e,M),e.classes.forEach(c.default.addClass.bind(null,M)),this.containers.push(M),this.data.push(e),I}},{key:"remove",value:function(A){var M=this.modals.indexOf(A);if(M!==-1){var t=i(this.data,A),I=this.data[t],g=this.containers[t];I.modals.splice(I.modals.indexOf(A),1),this.modals.splice(M,1),0===I.modals.length?(I.classes.forEach(c.default.removeClass.bind(null,g)),this.handleContainerOverflow&&E(I,g),this.hideSiblingNodes&&(0,r.showSiblings)(g,A.mountNode),this.containers.splice(t,1),this.data.splice(t,1)):this.hideSiblingNodes&&(0,r.ariaHidden)(!1,I.modals[I.modals.length-1].mountNode)}}},{key:"isTopModal",value:function(A){return!!this.modals.length&&this.modals[this.modals.length-1]===A}}]),A}();M.default=s,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){var t={};for(var I in A)M.indexOf(I)>=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=Object.assign||function(A){for(var M=1;M1?t-1:0),g=1;g=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}Object.defineProperty(M,"__esModule",{value:!0});var E=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function i(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function T(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}function E(){}Object.defineProperty(M,"__esModule",{value:!0}),M.EXITING=M.ENTERED=M.ENTERING=M.EXITED=M.UNMOUNTED=void 0;var N=Object.assign||function(A){for(var M=1;MT?T-N:0}function i(A,M,t,I){var e=g(t),i=e.width,T=A-I,E=A+I+M;return T<0?-T:E>i?i-E:0}function T(A,M,t,I,g){var T="BODY"===I.tagName?(0,N.default)(t):(0,n.default)(t,I),E=(0,N.default)(M),o=E.height,C=E.width,c=void 0,D=void 0,a=void 0,B=void 0;if("left"===A||"right"===A){D=T.top+(T.height-o)/2,c="left"===A?T.left-C:T.left+T.width;var Q=e(D,o,I,g);D+=Q,B=50*(1-2*Q/o)+"%",a=void 0}else{if("top"!==A&&"bottom"!==A)throw new Error('calcOverlayPosition(): No such placement of "'+A+'" found.');c=T.left+(T.width-C)/2,D="top"===A?T.top-o:T.top+T.height;var r=i(c,C,I,g);c+=r,a=50*(1-2*r/C)+"%",B=void 0}return{positionLeft:c,positionTop:D,arrowOffsetLeft:a,arrowOffsetTop:B}}Object.defineProperty(M,"__esModule",{value:!0}),M.default=T;var E=t(143),N=I(E),o=t(287),n=I(o),C=t(144),c=I(C),D=t(52),a=I(D);A.exports=M.default},function(A,M){"use strict";function t(A,M){M&&(A?M.setAttribute("aria-hidden","true"):M.removeAttribute("aria-hidden"))}function I(A,M){T(A,M,function(A){return t(!0,A)})}function g(A,M){T(A,M,function(A){return t(!1,A)})}Object.defineProperty(M,"__esModule",{value:!0}),M.ariaHidden=t,M.hideSiblings=I,M.showSiblings=g;var e=["template","script","style"],i=function(A){var M=A.nodeType,t=A.tagName;return 1===M&&e.indexOf(t.toLowerCase())===-1},T=function(A,M,t){M=[].concat(M),[].forEach.call(A.children,function(A){M.indexOf(A)===-1&&i(A)&&t(A)})}},function(A,M,t){"use strict";var I=function(){};A.exports=I},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){return function(t,I,g){if(null!=t[I]){var e='"'+I+'" property of "'+g+'" has been deprecated.\n'+M;E[e]||(T.default(!1,e),E[e]=!0)}return A(t,I,g)}}function e(){E={}}M.__esModule=!0,M.default=g;var i=t(127),T=I(i),E={};g._resetWarned=e,A.exports=M.default},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(A,M){if(!(A instanceof M))throw new TypeError("Cannot call a class as a function")}function e(A,M){if(!A)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!M||"object"!=typeof M&&"function"!=typeof M?A:M}function i(A,M){if("function"!=typeof M&&null!==M)throw new TypeError("Super expression must either be null or a function, not "+typeof M);A.prototype=Object.create(M&&M.prototype,{constructor:{value:A,enumerable:!1,writable:!0,configurable:!0}}),M&&(Object.setPrototypeOf?Object.setPrototypeOf(A,M):A.__proto__=M)}M.__esModule=!0,M.default=void 0;var T=t(1),E=t(184),N=I(E),o=t(185),n=(I(o),function(A){function M(t,I){g(this,M);var i=e(this,A.call(this,t,I));return i.store=t.store,i}return i(M,A),M.prototype.getChildContext=function(){return{store:this.store}},M.prototype.render=function(){return T.Children.only(this.props.children)},M}(T.Component));M.default=n,n.propTypes={store:N.default.isRequired,children:T.PropTypes.element.isRequired},n.childContextTypes={store:N.default.isRequired}},function(A,M){"use strict";function t(A,M){if(A===M)return!0;var t=Object.keys(A),I=Object.keys(M);if(t.length!==I.length)return!1;for(var g=Object.prototype.hasOwnProperty,e=0;e=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A,M){var t=A.history,I=A.routes,e=A.location,E=g(A,["history","routes","location"]);t||e?void 0:(0,N.default)(!1),t=t?t:(0,n.default)(E);var o=(0,c.default)(t,(0,D.createRoutes)(I)),C=void 0;e?e=t.createLocation(e):C=t.listen(function(A){e=A});var B=(0,a.createRouterObject)(t,o);t=(0,a.createRoutingHistory)(t,o),o.match(e,function(A,I,g){M(A,I&&B.createLocation(I,T.REPLACE),g&&i({},g,{history:t,router:B,matchContext:{history:t,transitionManager:o,router:B}})),C&&C()})}M.__esModule=!0;var i=Object.assign||function(A){for(var M=1;M=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function e(A){return function(){var M=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],t=M.routes,I=g(M,["routes"]),e=(0,E.default)(A)(I),T=(0,o.default)(e,t);return i({},e,T)}}M.__esModule=!0;var i=Object.assign||function(A){for(var M=1;M=A&&N&&(T=!0,t()))}}var i=0,T=!1,E=!1,N=!1,o=void 0;e()}M.__esModule=!0;var I=Array.prototype.slice;M.loopAsync=t},function(A,M,t){"use strict";function I(A){return A&&A.__esModule?A:{default:A}}function g(){function A(A){try{A=A||window.history.state||{}}catch(M){A={}}var M=n.getWindowPath(),t=A,I=t.key,g=void 0;I?g=C.readState(I):(g=null,I=s.createKey(),Q&&window.history.replaceState(e({},A,{key:I}),null));var i=N.parsePath(M);return s.createLocation(e({},i,{state:g}),void 0,I)}function M(M){function t(M){void 0!==M.state&&I(A(M.state))}var I=M.transitionTo;return n.addEventListener(window,"popstate",t),function(){n.removeEventListener(window,"popstate",t)}}function t(A){var M=A.basename,t=A.pathname,I=A.search,g=A.hash,e=A.state,i=A.action,T=A.key;if(i!==E.POP){C.saveState(T,e);var N=(M||"")+t+I+g,o={key:T};if(i===E.PUSH){if(r)return window.location.href=N,!1;window.history.pushState(o,null,N)}else{if(r)return window.location.replace(N),!1;window.history.replaceState(o,null,N)}}}function I(A){1===++x&&(j=M(s));var t=s.listenBefore(A);return function(){t(),0===--x&&j()}}function g(A){1===++x&&(j=M(s));var t=s.listen(A);return function(){t(),0===--x&&j()}}function i(A){1===++x&&(j=M(s)),s.registerTransitionHook(A)}function c(A){s.unregisterTransitionHook(A),0===--x&&j()}var a=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];o.canUseDOM?void 0:T.default(!1);var B=a.forceRefresh,Q=n.supportsHistory(),r=!Q||B,s=D.default(e({},a,{getCurrentLocation:A,finishTransition:t,saveState:C.saveState})),x=0,j=void 0;return e({},s,{listenBefore:I,listen:g,registerTransitionHook:i,unregisterTransitionHook:c})}M.__esModule=!0;var e=Object.assign||function(A){for(var M=1;M=0&&M=0&&B8&&u<=11),l=32,Y=String.fromCharCode(l),d=c.topLevelTypes,h={beforeInput:{phasedRegistrationNames:{bubbled:s({onBeforeInput:null}),captured:s({onBeforeInputCapture:null})},dependencies:[d.topCompositionEnd,d.topKeyPress,d.topTextInput,d.topPaste]},compositionEnd:{phasedRegistrationNames:{bubbled:s({onCompositionEnd:null}),captured:s({onCompositionEndCapture:null})},dependencies:[d.topBlur,d.topCompositionEnd,d.topKeyDown,d.topKeyPress,d.topKeyUp,d.topMouseDown]},compositionStart:{phasedRegistrationNames:{bubbled:s({onCompositionStart:null}),captured:s({onCompositionStartCapture:null})},dependencies:[d.topBlur,d.topCompositionStart,d.topKeyDown,d.topKeyPress,d.topKeyUp,d.topMouseDown]},compositionUpdate:{phasedRegistrationNames:{bubbled:s({onCompositionUpdate:null}),captured:s({onCompositionUpdateCapture:null})},dependencies:[d.topBlur,d.topCompositionUpdate,d.topKeyDown,d.topKeyPress,d.topKeyUp,d.topMouseDown]}},S=!1,z=null,p={eventTypes:h,extractEvents:function(A,M,t,I,g){return[N(A,M,t,I,g),C(A,M,t,I,g)]}};A.exports=p},function(A,M,t){"use strict";var I=t(202),g=t(10),e=t(17),i=(t(297),t(476)),T=t(302),E=t(306),N=(t(3),E(function(A){return T(A)})),o=!1,n="cssFloat";if(g.canUseDOM){var C=document.createElement("div").style;try{C.font=""}catch(A){o=!0}void 0===document.documentElement.style.cssFloat&&(n="styleFloat")}var c={createMarkupForStyles:function(A){var M="";for(var t in A)if(A.hasOwnProperty(t)){var I=A[t];null!=I&&(M+=N(t)+":",M+=i(t,I)+";")}return M||null},setValueForStyles:function(A,M){var t=A.style;for(var g in M)if(M.hasOwnProperty(g)){var e=i(g,M[g]);if("float"===g&&(g=n),e)t[g]=e;else{var T=o&&I.shorthandPropertyExpansions[g];if(T)for(var E in T)t[E]="";else t[g]=""}}}};e.measureMethods(c,"CSSPropertyOperations",{setValueForStyles:"setValueForStyles"}),A.exports=c},function(A,M,t){"use strict";function I(A){var M=A.nodeName&&A.nodeName.toLowerCase();return"select"===M||"input"===M&&"file"===A.type}function g(A){var M=u.getPooled(h.change,z,A,w(A));x.accumulateTwoPhaseDispatches(M),y.batchedUpdates(e,M)}function e(A){s.enqueueEvents(A),s.processEventQueue(!1)}function i(A,M){S=A,z=M,S.attachEvent("onchange",g)}function T(){S&&(S.detachEvent("onchange",g),S=null,z=null)}function E(A,M,t){if(A===d.topChange)return t}function N(A,M,t){A===d.topFocus?(T(),i(M,t)):A===d.topBlur&&T()}function o(A,M){S=A,z=M,p=A.value,U=Object.getOwnPropertyDescriptor(A.constructor.prototype,"value"),Object.defineProperty(S,"value",F),S.attachEvent("onpropertychange",C)}function n(){S&&(delete S.value,S.detachEvent("onpropertychange",C),S=null,z=null,p=null,U=null)}function C(A){if("value"===A.propertyName){var M=A.srcElement.value;M!==p&&(p=M,g(A))}}function c(A,M,t){if(A===d.topInput)return t}function D(A,M,t){A===d.topFocus?(n(),o(M,t)):A===d.topBlur&&n()}function a(A,M,t){if((A===d.topSelectionChange||A===d.topKeyUp||A===d.topKeyDown)&&S&&S.value!==p)return p=S.value,z}function B(A){return A.nodeName&&"input"===A.nodeName.toLowerCase()&&("checkbox"===A.type||"radio"===A.type)}function Q(A,M,t){if(A===d.topClick)return t}var r=t(24),s=t(53),x=t(54),j=t(10),y=t(18),u=t(37),w=t(117),L=t(120),l=t(229),Y=t(27),d=r.topLevelTypes,h={change:{phasedRegistrationNames:{bubbled:Y({onChange:null}),captured:Y({onChangeCapture:null})},dependencies:[d.topBlur,d.topChange,d.topClick,d.topFocus,d.topInput,d.topKeyDown,d.topKeyUp,d.topSelectionChange]}},S=null,z=null,p=null,U=null,O=!1;j.canUseDOM&&(O=L("change")&&(!("documentMode"in document)||document.documentMode>8));var m=!1;j.canUseDOM&&(m=L("input")&&(!("documentMode"in document)||document.documentMode>9));var F={get:function(){return U.get.call(this)},set:function(A){p=""+A,U.set.call(this,A)}},f={eventTypes:h,extractEvents:function(A,M,t,g,e){var i,T;if(I(M)?O?i=E:T=N:l(M)?m?i=c:(i=a,T=D):B(M)&&(i=Q),i){var o=i(A,M,t);if(o){var n=u.getPooled(h.change,o,g,e);return n.type="change",x.accumulateTwoPhaseDispatches(n),n}}T&&T(A,M,t)}};A.exports=f},function(A,M){"use strict";var t=0,I={createReactRootIndex:function(){return t++}};A.exports=I},function(A,M,t){"use strict";function I(A){return A.substring(1,A.indexOf(" "))}var g=t(10),e=t(299),i=t(20),T=t(151),E=t(2),N=/^(<[^ \/>]+)/,o="data-danger-index",n={dangerouslyRenderMarkup:function(A){g.canUseDOM?void 0:E(!1);for(var M,t={},n=0;n1?1-M:void 0;return this._fallbackText=g.slice(A,T),this._fallbackText}}),g.addPoolingTo(I),A.exports=I},function(A,M,t){"use strict";var I,g=t(47),e=t(10),i=g.injection.MUST_USE_ATTRIBUTE,T=g.injection.MUST_USE_PROPERTY,E=g.injection.HAS_BOOLEAN_VALUE,N=g.injection.HAS_SIDE_EFFECTS,o=g.injection.HAS_NUMERIC_VALUE,n=g.injection.HAS_POSITIVE_NUMERIC_VALUE,C=g.injection.HAS_OVERLOADED_BOOLEAN_VALUE;if(e.canUseDOM){var c=document.implementation;I=c&&c.hasFeature&&c.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1")}var D={isCustomAttribute:RegExp.prototype.test.bind(/^(data|aria)-[a-z_][a-z\d_.\-]*$/),Properties:{accept:null,acceptCharset:null,accessKey:null,action:null,allowFullScreen:i|E,allowTransparency:i,alt:null,async:E,autoComplete:null,autoPlay:E,capture:i|E,cellPadding:null,cellSpacing:null,charSet:i,challenge:i,checked:T|E,classID:i,className:I?i:T,cols:i|n,colSpan:null,content:null,contentEditable:null,contextMenu:i,controls:T|E,coords:null,crossOrigin:null,data:null,dateTime:i,default:E,defer:E,dir:null,disabled:i|E,download:C,draggable:null,encType:null,form:i,formAction:i,formEncType:i,formMethod:i,formNoValidate:E,formTarget:i,frameBorder:i,headers:null,height:i,hidden:i|E,high:null,href:null,hrefLang:null,htmlFor:null,httpEquiv:null,icon:null,id:T,inputMode:i,integrity:null,is:i,keyParams:i,keyType:i,kind:null,label:null,lang:null,list:i,loop:T|E,low:null,manifest:i,marginHeight:null,marginWidth:null,max:null,maxLength:i,media:i,mediaGroup:null,method:null,min:null,minLength:i,multiple:T|E,muted:T|E,name:null,nonce:i,noValidate:E,open:E,optimum:null,pattern:null,placeholder:null,poster:null,preload:null,radioGroup:null,readOnly:T|E,rel:null,required:E,reversed:E,role:i,rows:i|n,rowSpan:null,sandbox:null,scope:null,scoped:E,scrolling:null,seamless:i|E,selected:T|E,shape:null,size:i|n,sizes:i,span:n,spellCheck:null,src:null,srcDoc:T,srcLang:null,srcSet:i,start:o,step:null,style:null,summary:null,tabIndex:null,target:null,title:null,type:null,useMap:null,value:T|N,width:i,wmode:i,wrap:null,about:i,datatype:i,inlist:i,prefix:i,property:i,resource:i,typeof:i,vocab:i,autoCapitalize:i,autoCorrect:i,autoSave:null,color:null,itemProp:i,itemScope:i|E,itemType:i,itemID:i,itemRef:i,results:null,security:i,unselectable:i},DOMAttributeNames:{acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},DOMPropertyNames:{autoComplete:"autocomplete",autoFocus:"autofocus",autoPlay:"autoplay",autoSave:"autosave",encType:"encoding",hrefLang:"hreflang",radioGroup:"radiogroup",spellCheck:"spellcheck",srcDoc:"srcdoc",srcSet:"srcset"}};A.exports=D},function(A,M,t){"use strict";var I=t(208),g=t(450),e=t(455),i=t(4),T=t(477),E={};i(E,e),i(E,{findDOMNode:T("findDOMNode","ReactDOM","react-dom",I,I.findDOMNode),render:T("render","ReactDOM","react-dom",I,I.render),unmountComponentAtNode:T("unmountComponentAtNode","ReactDOM","react-dom",I,I.unmountComponentAtNode),renderToString:T("renderToString","ReactDOMServer","react-dom/server",g,g.renderToString),renderToStaticMarkup:T("renderToStaticMarkup","ReactDOMServer","react-dom/server",g,g.renderToStaticMarkup)}),E.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=I,E.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=g,A.exports=E},function(A,M,t){"use strict";var I=(t(55),t(114)),g=(t(3),"_getDOMNodeDidWarn"),e={getDOMNode:function(){return this.constructor[g]=!0,I(this)}};A.exports=e},function(A,M,t){"use strict";function I(A,M,t){var I=void 0===A[t];null!=M&&I&&(A[t]=e(M,null))}var g=t(36),e=t(119),i=t(122),T=t(123),E=(t(3),{instantiateChildren:function(A,M,t){if(null==A)return null;var g={};return T(A,I,g),g},updateChildren:function(A,M,t,I){if(!M&&!A)return null;var T;for(T in M)if(M.hasOwnProperty(T)){var E=A&&A[T],N=E&&E._currentElement,o=M[T];if(null!=E&&i(N,o))g.receiveComponent(E,o,t,I),M[T]=E;else{E&&g.unmountComponent(E,T);var n=e(o,null);M[T]=n}}for(T in A)!A.hasOwnProperty(T)||M&&M.hasOwnProperty(T)||g.unmountComponent(A[T]);return M},unmountChildren:function(A){for(var M in A)if(A.hasOwnProperty(M)){var t=A[M];g.unmountComponent(t)}}});A.exports=E},function(A,M,t){"use strict";function I(A){var M=A._currentElement._owner||null;if(M){var t=M.getName();if(t)return" Check the render method of ` + "`" + `"+t+"` + "`" + `."}return""}function g(A){}var e=t(110),i=t(25),T=t(13),E=t(55),N=t(17),o=t(71),n=(t(70),t(36)),C=t(112),c=t(4),D=t(50),a=t(2),B=t(122);t(3);g.prototype.render=function(){var A=E.get(this)._currentElement.type;return A(this.props,this.context,this.updater)};var Q=1,r={construct:function(A){this._currentElement=A,this._rootNodeID=null,this._instance=null,this._pendingElement=null,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._renderedComponent=null,this._context=null,this._mountOrder=0,this._topLevelWrapper=null,this._pendingCallbacks=null},mountComponent:function(A,M,t){this._context=t,this._mountOrder=Q++,this._rootNodeID=A;var I,e,i=this._processProps(this._currentElement.props),N=this._processContext(t),o=this._currentElement.type,c="prototype"in o;c&&(I=new o(i,N,C)),c&&null!==I&&I!==!1&&!T.isValidElement(I)||(e=I,I=new g(o)),I.props=i,I.context=N,I.refs=D,I.updater=C,this._instance=I,E.set(I,this);var B=I.state;void 0===B&&(I.state=B=null),"object"!=typeof B||Array.isArray(B)?a(!1):void 0,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,I.componentWillMount&&(I.componentWillMount(),this._pendingStateQueue&&(I.state=this._processPendingState(I.props,I.context))),void 0===e&&(e=this._renderValidatedComponent()),this._renderedComponent=this._instantiateReactComponent(e);var r=n.mountComponent(this._renderedComponent,A,M,this._processChildContext(t));return I.componentDidMount&&M.getReactMountReady().enqueue(I.componentDidMount,I),r},unmountComponent:function(){var A=this._instance;A.componentWillUnmount&&A.componentWillUnmount(),n.unmountComponent(this._renderedComponent),this._renderedComponent=null,this._instance=null,this._pendingStateQueue=null,this._pendingReplaceState=!1,this._pendingForceUpdate=!1,this._pendingCallbacks=null,this._pendingElement=null,this._context=null,this._rootNodeID=null,this._topLevelWrapper=null,E.remove(A)},_maskContext:function(A){var M=null,t=this._currentElement.type,I=t.contextTypes;if(!I)return D;M={};for(var g in I)M[g]=A[g];return M},_processContext:function(A){var M=this._maskContext(A);return M},_processChildContext:function(A){var M=this._currentElement.type,t=this._instance,I=t.getChildContext&&t.getChildContext();if(I){"object"!=typeof M.childContextTypes?a(!1):void 0;for(var g in I)g in M.childContextTypes?void 0:a(!1);return c({},A,I)}return A},_processProps:function(A){return A},_checkPropTypes:function(A,M,t){var g=this.getName();for(var e in A)if(A.hasOwnProperty(e)){var i;try{"function"!=typeof A[e]?a(!1):void 0,i=A[e](M,e,g,t)}catch(A){i=A}if(i instanceof Error){I(this);t===o.prop}}},receiveComponent:function(A,M,t){var I=this._currentElement,g=this._context;this._pendingElement=null,this.updateComponent(M,I,A,g,t)},performUpdateIfNecessary:function(A){null!=this._pendingElement&&n.receiveComponent(this,this._pendingElement||this._currentElement,A,this._context),(null!==this._pendingStateQueue||this._pendingForceUpdate)&&this.updateComponent(A,this._currentElement,this._currentElement,this._context,this._context)},updateComponent:function(A,M,t,I,g){var e,i=this._instance,T=this._context===g?i.context:this._processContext(g);M===t?e=t.props:(e=this._processProps(t.props),i.componentWillReceiveProps&&i.componentWillReceiveProps(e,T));var E=this._processPendingState(e,T),N=this._pendingForceUpdate||!i.shouldComponentUpdate||i.shouldComponentUpdate(e,E,T);N?(this._pendingForceUpdate=!1,this._performComponentUpdate(t,e,E,T,A,g)):(this._currentElement=t,this._context=g,i.props=e,i.state=E,i.context=T)},_processPendingState:function(A,M){var t=this._instance,I=this._pendingStateQueue,g=this._pendingReplaceState;if(this._pendingReplaceState=!1,this._pendingStateQueue=null,!I)return t.state;if(g&&1===I.length)return I[0];for(var e=c({},g?I[0]:t.state),i=g?1:0;i=0||null!=M.is}function B(A){D(A),this._tag=A.toLowerCase(),this._renderedChildren=null,this._previousStyle=null,this._previousStyleCopy=null,this._rootNodeID=null,this._wrapperState=null,this._topLevelWrapper=null,this._nodeWithLegacyProperties=null}var Q=t(429),r=t(431),s=t(47),x=t(107),j=t(24),y=t(69),u=t(109),w=t(444),L=t(447),l=t(448),Y=t(210),d=t(451),h=t(12),S=t(456),z=t(17),p=t(112),U=t(4),O=t(74),m=t(75),F=t(2),f=(t(120),t(27)),k=t(76),R=t(121),J=(t(152),t(124),t(3),y.deleteListener),G=y.listenTo,H=y.registrationNameModules,b={string:!0,number:!0},X=f({children:null}),v=f({style:null}),W=f({__html:null}),V=1,P={topAbort:"abort",topCanPlay:"canplay",topCanPlayThrough:"canplaythrough",topDurationChange:"durationchange",topEmptied:"emptied",topEncrypted:"encrypted",topEnded:"ended",topError:"error",topLoadedData:"loadeddata",topLoadedMetadata:"loadedmetadata",topLoadStart:"loadstart",topPause:"pause",topPlay:"play",topPlaying:"playing",topProgress:"progress",topRateChange:"ratechange",topSeeked:"seeked",topSeeking:"seeking",topStalled:"stalled",topSuspend:"suspend",topTimeUpdate:"timeupdate",topVolumeChange:"volumechange",topWaiting:"waiting"},Z={area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},K={listing:!0,pre:!0,textarea:!0},q=(U({menuitem:!0},Z),/^[a-zA-Z][a-zA-Z:_\.\-\d]*$/),_={},$={}.hasOwnProperty;B.displayName="ReactDOMComponent",B.Mixin={construct:function(A){this._currentElement=A},mountComponent:function(A,M,t){this._rootNodeID=A;var I=this._currentElement.props;switch(this._tag){case"iframe":case"img":case"form":case"video":case"audio":this._wrapperState={listeners:null},M.getReactMountReady().enqueue(n,this);break;case"button":I=w.getNativeProps(this,I,t);break;case"input":L.mountWrapper(this,I,t),I=L.getNativeProps(this,I,t);break;case"option":l.mountWrapper(this,I,t),I=l.getNativeProps(this,I,t);break;case"select":Y.mountWrapper(this,I,t),I=Y.getNativeProps(this,I,t),t=Y.processChildContext(this,I,t);break;case"textarea":d.mountWrapper(this,I,t),I=d.getNativeProps(this,I,t)}E(this,I);var g;if(M.useCreateElement){var e=t[h.ownerDocumentContextKey],i=e.createElement(this._currentElement.type);x.setAttributeForID(i,this._rootNodeID),h.getID(i),this._updateDOMProperties({},I,M,i),this._createInitialChildren(M,I,t,i),g=i}else{var T=this._createOpenTagMarkupAndPutListeners(M,I),N=this._createContentMarkup(M,I,t);g=!N&&Z[this._tag]?T+"/>":T+">"+N+""}switch(this._tag){case"input":M.getReactMountReady().enqueue(C,this);case"button":case"select":case"textarea":I.autoFocus&&M.getReactMountReady().enqueue(Q.focusDOMComponent,this)}return g},_createOpenTagMarkupAndPutListeners:function(A,M){var t="<"+this._currentElement.type;for(var I in M)if(M.hasOwnProperty(I)){var g=M[I];if(null!=g)if(H.hasOwnProperty(I))g&&N(this._rootNodeID,I,g,A);else{I===v&&(g&&(g=this._previousStyleCopy=U({},M.style)),g=r.createMarkupForStyles(g));var e=null;null!=this._tag&&a(this._tag,M)?I!==X&&(e=x.createMarkupForCustomAttribute(I,g)):e=x.createMarkupForProperty(I,g),e&&(t+=" "+e)}}if(A.renderToStaticMarkup)return t;var i=x.createMarkupForID(this._rootNodeID);return t+" "+i},_createContentMarkup:function(A,M,t){var I="",g=M.dangerouslySetInnerHTML;if(null!=g)null!=g.__html&&(I=g.__html);else{var e=b[typeof M.children]?M.children:null,i=null!=e?null:M.children;if(null!=e)I=m(e);else if(null!=i){var T=this.mountChildren(i,A,t);I=T.join("")}}return K[this._tag]&&"\n"===I.charAt(0)?"\n"+I:I},_createInitialChildren:function(A,M,t,I){var g=M.dangerouslySetInnerHTML;if(null!=g)null!=g.__html&&k(I,g.__html);else{var e=b[typeof M.children]?M.children:null,i=null!=e?null:M.children;if(null!=e)R(I,e);else if(null!=i)for(var T=this.mountChildren(i,A,t),E=0;EM.end?(t=M.end,I=M.start):(t=M.start,I=M.end),g.moveToElementText(A),g.moveStart("character",t),g.setEndPoint("EndToStart",g),g.moveEnd("character",I-t),g.select()}function T(A,M){if(window.getSelection){var t=window.getSelection(),I=A[o()].length,g=Math.min(M.start,I),e="undefined"==typeof M.end?g:Math.min(M.end,I);if(!t.extend&&g>e){var i=e;e=g,g=i}var T=N(A,g),E=N(A,e);if(T&&E){var n=document.createRange();n.setStart(T.node,T.offset),t.removeAllRanges(),g>e?(t.addRange(n),t.extend(E.node,E.offset)):(n.setEnd(E.node,E.offset),t.addRange(n))}}}var E=t(10),N=t(480),o=t(228),n=E.canUseDOM&&"selection"in document&&!("getSelection"in window),C={getOffsets:n?g:e,setOffsets:n?i:T};A.exports=C},function(A,M,t){"use strict";var I=t(213),g=t(461),e=t(113);I.inject();var i={renderToString:g.renderToString,renderToStaticMarkup:g.renderToStaticMarkup,version:e};A.exports=i},function(A,M,t){"use strict";function I(){this._rootNodeID&&o.updateWrapper(this)}function g(A){var M=this._currentElement.props,t=e.executeOnChange(M,A);return T.asap(I,this),t}var e=t(108),i=t(111),T=t(18),E=t(4),N=t(2),o=(t(3),{getNativeProps:function(A,M,t){null!=M.dangerouslySetInnerHTML?N(!1):void 0;var I=E({},M,{defaultValue:void 0,value:void 0,children:A._wrapperState.initialValue,onChange:A._wrapperState.onChange});return I},mountWrapper:function(A,M){var t=M.defaultValue,I=M.children;null!=I&&(null!=t?N(!1):void 0,Array.isArray(I)&&(I.length<=1?void 0:N(!1),I=I[0]),t=""+I),null==t&&(t="");var i=e.getValue(M);A._wrapperState={initialValue:""+(null!=i?i:t),onChange:g.bind(A)}},updateWrapper:function(A){var M=A._currentElement.props,t=e.getValue(M);null!=t&&i.updatePropertyByID(A._rootNodeID,"value",""+t)}});A.exports=o},function(A,M,t){"use strict";function I(A){g.enqueueEvents(A),g.processEventQueue(!1)}var g=t(53),e={handleTopLevel:function(A,M,t,e,i){var T=g.extractEvents(A,M,t,e,i);I(T)}};A.exports=e},function(A,M,t){"use strict";function I(A){var M=C.getID(A),t=n.getReactRootIDFromNodeID(M),I=C.findReactContainerForID(t),g=C.getFirstReactDOM(I);return g}function g(A,M){this.topLevelType=A,this.nativeEvent=M,this.ancestors=[]}function e(A){i(A)}function i(A){for(var M=C.getFirstReactDOM(a(A.nativeEvent))||window,t=M;t;)A.ancestors.push(t),t=I(t);for(var g=0;g=M)return{node:g,offset:M-e};e=i}g=t(I(g))}}A.exports=g},function(A,M,t){"use strict";function I(A){return g.isValidElement(A)?void 0:e(!1),A}var g=t(13),e=t(2);A.exports=I},function(A,M,t){"use strict";function I(A){return'"'+g(A)+'"'}var g=t(75);A.exports=I},function(A,M,t){"use strict";var I=t(12);A.exports=I.renderSubtreeIntoContainer},function(A,M){A.exports=function(A,M,t){for(var I=0,g=A.length,e=3==arguments.length?t:A[I++];I=400){ +var T="cannot "+M.method+" "+M.url+" ("+i.status+")";A=new e(T),A.status=i.status,A.body=i.body,A.res=i,I(A)}else g?I(new e(g)):t(i)})})},g.prototype.then=function(){var A=this.promise();return A.then.apply(A,arguments)}},function(A,M,t){function I(){}function g(A){var M={}.toString.call(A);switch(M){case"[object File]":case"[object Blob]":case"[object FormData]":return!0;default:return!1}}function e(A){if(!s(A))return A;var M=[];for(var t in A)null!=A[t]&&i(M,t,A[t]);return M.join("&")}function i(A,M,t){return Array.isArray(t)?t.forEach(function(t){i(A,M,t)}):void A.push(encodeURIComponent(M)+"="+encodeURIComponent(t))}function T(A){for(var M,t,I={},g=A.split("&"),e=0,i=g.length;e=200&&M.status<300)return t.callback(A,M);var I=new Error(M.statusText||"Unsuccessful HTTP response");I.original=A,I.response=M,I.status=M.status,t.callback(I,M)})}function D(A,M){var t=x("DELETE",A);return M&&t.end(M),t}var a,B=t(273),Q=t(484),r=t(502),s=t(236);a="undefined"!=typeof window?window:"undefined"!=typeof self?self:this;var x=A.exports=t(503).bind(null,c);x.getXHR=function(){if(!(!a.XMLHttpRequest||a.location&&"file:"==a.location.protocol&&a.ActiveXObject))return new XMLHttpRequest;try{return new ActiveXObject("Microsoft.XMLHTTP")}catch(A){}try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(A){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(A){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(A){}return!1};var j="".trim?function(A){return A.trim()}:function(A){return A.replace(/(^\s*|\s*$)/g,"")};x.serializeObject=e,x.parseString=T,x.types={html:"text/html",json:"application/json",xml:"application/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},x.serialize={"application/x-www-form-urlencoded":e,"application/json":JSON.stringify},x.parse={"application/x-www-form-urlencoded":T,"application/json":JSON.parse},C.prototype.get=function(A){return this.header[A.toLowerCase()]},C.prototype.setHeaderProperties=function(A){var M=this.header["content-type"]||"";this.type=o(M);var t=n(M);for(var I in t)this[I]=t[I]},C.prototype.parseBody=function(A){var M=x.parse[this.type];return!M&&N(this.type)&&(M=x.parse["application/json"]),M&&A&&(A.length||A instanceof Object)?M(A):null},C.prototype.setStatusProperties=function(A){1223===A&&(A=204);var M=A/100|0;this.status=this.statusCode=A,this.statusType=M,this.info=1==M,this.ok=2==M,this.clientError=4==M,this.serverError=5==M,this.error=(4==M||5==M)&&this.toError(),this.accepted=202==A,this.noContent=204==A,this.badRequest=400==A,this.unauthorized=401==A,this.notAcceptable=406==A,this.notFound=404==A,this.forbidden=403==A},C.prototype.toError=function(){var A=this.req,M=A.method,t=A.url,I="cannot "+M+" "+t+" ("+this.status+")",g=new Error(I);return g.status=this.status,g.method=M,g.url=t,g},x.Response=C,B(c.prototype);for(var y in r)c.prototype[y]=r[y];c.prototype.abort=function(){if(!this.aborted)return this.aborted=!0,this.xhr&&this.xhr.abort(),this.clearTimeout(),this.emit("abort"),this},c.prototype.type=function(A){return this.set("Content-Type",x.types[A]||A),this},c.prototype.responseType=function(A){return this._responseType=A,this},c.prototype.accept=function(A){return this.set("Accept",x.types[A]||A),this},c.prototype.auth=function(A,M,t){switch(t||(t={type:"basic"}),t.type){case"basic":var I=btoa(A+":"+M);this.set("Authorization","Basic "+I);break;case"auto":this.username=A,this.password=M}return this},c.prototype.query=function(A){return"string"!=typeof A&&(A=e(A)),A&&this._query.push(A),this},c.prototype.attach=function(A,M,t){return this._getFormData().append(A,M,t||M.name),this},c.prototype._getFormData=function(){return this._formData||(this._formData=new a.FormData),this._formData},c.prototype.send=function(A){var M=s(A),t=this._header["content-type"];if(M&&s(this._data))for(var I in A)this._data[I]=A[I];else"string"==typeof A?(t||this.type("form"),t=this._header["content-type"],"application/x-www-form-urlencoded"==t?this._data=this._data?this._data+"&"+A:A:this._data=(this._data||"")+A):this._data=A;return!M||g(A)?this:(t||this.type("json"),this)},C.prototype.parse=function(A){return a.console&&console.warn("Client-side parse() method has been renamed to serialize(). This method is not compatible with superagent v2.0"),this.serialize(A),this},C.prototype.serialize=function(A){return this._parser=A,this},c.prototype.callback=function(A,M){var t=this._callback;this.clearTimeout(),t(A,M)},c.prototype.crossDomainError=function(){var A=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");A.crossDomain=!0,A.status=this.status,A.method=this.method,A.url=this.url,this.callback(A)},c.prototype.timeoutError=function(){var A=this._timeout,M=new Error("timeout of "+A+"ms exceeded");M.timeout=A,this.callback(M)},c.prototype.withCredentials=function(){return this._withCredentials=!0,this},c.prototype.end=function(A){var M=this,t=this.xhr=x.getXHR(),e=this._query.join("&"),i=this._timeout,T=this._formData||this._data;this._callback=A||I,t.onreadystatechange=function(){if(4==t.readyState){var A;try{A=t.status}catch(M){A=0}if(0==A){if(M.timedout)return M.timeoutError();if(M.aborted)return;return M.crossDomainError()}M.emit("end")}};var E=function(A){A.total>0&&(A.percent=A.loaded/A.total*100),A.direction="download",M.emit("progress",A)};this.hasListeners("progress")&&(t.onprogress=E);try{t.upload&&this.hasListeners("progress")&&(t.upload.onprogress=E)}catch(A){}if(i&&!this._timer&&(this._timer=setTimeout(function(){M.timedout=!0,M.abort()},i)),e&&(e=x.serializeObject(e),this.url+=~this.url.indexOf("?")?"&"+e:"?"+e),this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0),this._withCredentials&&(t.withCredentials=!0),"GET"!=this.method&&"HEAD"!=this.method&&"string"!=typeof T&&!g(T)){var o=this._header["content-type"],n=this._parser||x.serialize[o?o.split(";")[0]:""];!n&&N(o)&&(n=x.serialize["application/json"]),n&&(T=n(T))}for(var C in this.header)null!=this.header[C]&&t.setRequestHeader(C,this.header[C]);return this._responseType&&(t.responseType=this._responseType),this.emit("request",this),t.send("undefined"!=typeof T?T:null),this},x.Request=c,x.get=function(A,M,t){var I=x("GET",A);return"function"==typeof M&&(t=M,M=null),M&&I.query(M),t&&I.end(t),I},x.head=function(A,M,t){var I=x("HEAD",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I},x.del=D,x.delete=D,x.patch=function(A,M,t){var I=x("PATCH",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I},x.post=function(A,M,t){var I=x("POST",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I},x.put=function(A,M,t){var I=x("PUT",A);return"function"==typeof M&&(t=M,M=null),M&&I.send(M),t&&I.end(t),I}},function(A,M,t){var I=t(236);M.clearTimeout=function(){return this._timeout=0,clearTimeout(this._timer),this},M.parse=function(A){return this._parser=A,this},M.timeout=function(A){return this._timeout=A,this},M.then=function(A,M){return this.end(function(t,I){t?M(t):A(I)})},M.use=function(A){return A(this),this},M.get=function(A){return this._header[A.toLowerCase()]},M.getHeader=M.get,M.set=function(A,M){if(I(A)){for(var t in A)this.set(t,A[t]);return this}return this._header[A.toLowerCase()]=M,this.header[A]=M,this},M.unset=function(A){return delete this._header[A.toLowerCase()],delete this.header[A],this},M.field=function(A,M){return this._getFormData().append(A,M),this}},function(A,M){function t(A,M,t){return"function"==typeof t?new A("GET",M).end(t):2==arguments.length?new A("GET",M):new A(M,t)}A.exports=t},function(A,M,t){A.exports=t(505)},function(A,M,t){(function(A,I){"use strict";function g(A){return A&&A.__esModule?A:{default:A}}Object.defineProperty(M,"__esModule",{value:!0});var e,i=t(506),T=g(i);e="undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof A?A:I;var E=(0,T.default)(e);M.default=E}).call(M,function(){return this}(),t(128)(A))},function(A,M){"use strict";function t(A){var M,t=A.Symbol;return"function"==typeof t?t.observable?M=t.observable:(M=t("observable"),t.observable=M):M="@@observable",M}Object.defineProperty(M,"__esModule",{value:!0}),M.default=t},function(A,M,t){function I(A){return g(A).replace(/\s(\w)/g,function(A,M){return M.toUpperCase()})}var g=t(509);A.exports=I},function(A,M){function t(A){return e.test(A)?A.toLowerCase():i.test(A)?(I(A)||A).toLowerCase():T.test(A)?g(A).toLowerCase():A.toLowerCase()}function I(A){return A.replace(E,function(A,M){return M?" "+M:""})}function g(A){return A.replace(N,function(A,M,t){return M+" "+t.toLowerCase().split("").join(" ")})}A.exports=t;var e=/\s/,i=/(_|-|\.|:)/,T=/([a-z][A-Z]|[A-Z][a-z])/,E=/[\W_]+(.|$)/g,N=/(.)([A-Z]+)/g},function(A,M,t){function I(A){return g(A).replace(/[\W_]+(.|$)/g,function(A,M){return M?" "+M:""}).trim()}var g=t(508);A.exports=I},function(A,M){A.exports=function(){var A=document.getSelection();if(!A.rangeCount)return function(){};for(var M=document.activeElement,t=[],I=0;I=0||Object.prototype.hasOwnProperty.call(A,I)&&(t[I]=A[I]);return t}function i(A,M){function t(I,g){function i(A,t){var I=c.getLinkName(A),e=this.props[g[A]];I&&E(this.props,I)&&!e&&(e=this.props[I].requestChange);for(var i=arguments.length,T=Array(i>2?i-2:0),N=2;N=15||0===s[0]&&s[1]>=13?A:A.type}function T(A,M){var t=N(M);return t&&!E(A,M)&&E(A,t)?A[t].value:A[M]}function E(A,M){return void 0!==A[M]}function N(A){return"value"===A?"valueLink":"checked"===A?"checkedLink":null}function o(A){return"default"+A.charAt(0).toUpperCase()+A.substr(1)}function n(A,M,t){return function(){for(var I=arguments.length,g=Array(I),e=0;e1&&(I=t[0]+"@",A=t[1]),A=A.replace(z,".");var g=A.split("."),e=T(g,M).join(".");return I+e}function N(A){for(var M,t,I=[],g=0,e=A.length;g=55296&&M<=56319&&g65535&&(A-=65536,M+=m(A>>>10&1023|55296),A=56320|1023&A),M+=m(A)}).join("")}function n(A){return A-48<10?A-22:A-65<26?A-65:A-97<26?A-97:j}function C(A,M){return A+22+75*(A<26)-((0!=M)<<5)}function c(A,M,t){var I=0;for(A=t?O(A/L):A>>1,A+=O(A/M);A>p*u>>1;I+=j)A=O(A/p);return O(I+(p+1)*A/(A+w))}function D(A){var M,t,I,g,e,T,E,N,C,D,a=[],B=A.length,Q=0,r=Y,s=l;for(t=A.lastIndexOf(d),t<0&&(t=0),I=0;I=128&&i("not-basic"),a.push(A.charCodeAt(I));for(g=t>0?t+1:0;g=B&&i("invalid-input"),N=n(A.charCodeAt(g++)),(N>=j||N>O((x-Q)/T))&&i("overflow"),Q+=N*T,C=E<=s?y:E>=s+u?u:E-s,!(NO(x/D)&&i("overflow"),T*=D;M=a.length+1,s=c(Q-e,M,0==e),O(Q/M)>x-r&&i("overflow"),r+=O(Q/M),Q%=M,a.splice(Q++,0,r)}return o(a)}function a(A){var M,t,I,g,e,T,E,o,n,D,a,B,Q,r,s,w=[];for(A=N(A),B=A.length,M=Y,t=0,e=l,T=0;T=M&&aO((x-t)/Q)&&i("overflow"),t+=(E-M)*Q,M=E,T=0;Tx&&i("overflow"),a==M){for(o=t,n=j;D=n<=e?y:n>=e+u?u:n-e,!(o= 0x80 (not a basic code point)","invalid-input":"Invalid input"},p=j-y,O=Math.floor,m=String.fromCharCode;s={version:"1.3.2",ucs2:{decode:N,encode:o},decode:D,encode:a,toASCII:Q,toUnicode:B},I=function(){return s}.call(M,t,M,A),!(void 0!==I&&(A.exports=I))}(this)}).call(M,t(128)(A),function(){return this}())},function(A,M){"use strict";A.exports={isString:function(A){return"string"==typeof A},isObject:function(A){return"object"==typeof A&&null!==A},isNull:function(A){return null===A},isNullOrUndefined:function(A){return null==A}}}]);`) +},function(A,M,t){var I;(function(A,g){!function(e){function i(A){throw RangeError(p[A])}function T(A,M){for(var t=A.length,I=[];t--;)I[t]=M(A[t]);return I}function E(A,M){var t=A.split("@"),I="";t.length>1&&(I=t[0]+"@",A=t[1]),A=A.replace(z,".");var g=A.split("."),e=T(g,M).join(".");return I+e}function N(A){for(var M,t,I=[],g=0,e=A.length;g=55296&&M<=56319&&g65535&&(A-=65536,M+=m(A>>>10&1023|55296),A=56320|1023&A),M+=m(A)}).join("")}function n(A){return A-48<10?A-22:A-65<26?A-65:A-97<26?A-97:j}function C(A,M){return A+22+75*(A<26)-((0!=M)<<5)}function c(A,M,t){var I=0;for(A=t?O(A/L):A>>1,A+=O(A/M);A>U*u>>1;I+=j)A=O(A/U);return O(I+(U+1)*A/(A+w))}function D(A){var M,t,I,g,e,T,E,N,C,D,a=[],B=A.length,Q=0,r=Y,s=l;for(t=A.lastIndexOf(d),t<0&&(t=0),I=0;I=128&&i("not-basic"),a.push(A.charCodeAt(I));for(g=t>0?t+1:0;g=B&&i("invalid-input"),N=n(A.charCodeAt(g++)),(N>=j||N>O((x-Q)/T))&&i("overflow"),Q+=N*T,C=E<=s?y:E>=s+u?u:E-s,!(NO(x/D)&&i("overflow"),T*=D;M=a.length+1,s=c(Q-e,M,0==e),O(Q/M)>x-r&&i("overflow"),r+=O(Q/M),Q%=M,a.splice(Q++,0,r)}return o(a)}function a(A){var M,t,I,g,e,T,E,o,n,D,a,B,Q,r,s,w=[];for(A=N(A),B=A.length,M=Y,t=0,e=l,T=0;T=M&&aO((x-t)/Q)&&i("overflow"),t+=(E-M)*Q,M=E,T=0;Tx&&i("overflow"),a==M){for(o=t,n=j;D=n<=e?y:n>=e+u?u:n-e,!(o= 0x80 (not a basic code point)","invalid-input":"Invalid input"},U=j-y,O=Math.floor,m=String.fromCharCode;s={version:"1.3.2",ucs2:{decode:N,encode:o},decode:D,encode:a,toASCII:Q,toUnicode:B},I=function(){return s}.call(M,t,M,A),!(void 0!==I&&(A.exports=I))}(this)}).call(M,t(128)(A),function(){return this}())},function(A,M){"use strict";A.exports={isString:function(A){return"string"==typeof A},isObject:function(A){return"object"==typeof A&&null!==A},isNull:function(A){return null===A},isNullOrUndefined:function(A){return null==A}}}]);`) -func productionIndex_bundle20170125t031051zJsBytes() ([]byte, error) { - return _productionIndex_bundle20170125t031051zJs, nil +func productionIndex_bundle20170215t224123zJsBytes() ([]byte, error) { + return _productionIndex_bundle20170215t224123zJs, nil } -func productionIndex_bundle20170125t031051zJs() (*asset, error) { - bytes, err := productionIndex_bundle20170125t031051zJsBytes() +func productionIndex_bundle20170215t224123zJs() (*asset, error) { + bytes, err := productionIndex_bundle20170215t224123zJsBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "production/index_bundle-2017-01-25T03-10-51Z.js", size: 2272141, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/index_bundle-2017-02-15T22-41-23Z.js", size: 2276858, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -370,7 +370,7 @@ func productionLoaderCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/loader.css", size: 1738, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/loader.css", size: 1738, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -444,7 +444,7 @@ func productionLogoSvg() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/logo.svg", size: 3079, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/logo.svg", size: 3079, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -461,7 +461,7 @@ func productionSafariPng() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "production/safari.png", size: 4971, mode: os.FileMode(436), modTime: time.Unix(1485313867, 0)} + info := bindataFileInfo{name: "production/safari.png", size: 4971, mode: os.FileMode(436), modTime: time.Unix(1487198497, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -522,7 +522,7 @@ var _bindata = map[string]func() (*asset, error){ "production/favicon.ico": productionFaviconIco, "production/firefox.png": productionFirefoxPng, "production/index.html": productionIndexHTML, - "production/index_bundle-2017-01-25T03-10-51Z.js": productionIndex_bundle20170125t031051zJs, + "production/index_bundle-2017-02-15T22-41-23Z.js": productionIndex_bundle20170215t224123zJs, "production/loader.css": productionLoaderCss, "production/logo.svg": productionLogoSvg, "production/safari.png": productionSafariPng, @@ -574,7 +574,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "favicon.ico": {productionFaviconIco, map[string]*bintree{}}, "firefox.png": {productionFirefoxPng, map[string]*bintree{}}, "index.html": {productionIndexHTML, map[string]*bintree{}}, - "index_bundle-2017-01-25T03-10-51Z.js": {productionIndex_bundle20170125t031051zJs, map[string]*bintree{}}, + "index_bundle-2017-02-15T22-41-23Z.js": {productionIndex_bundle20170215t224123zJs, map[string]*bintree{}}, "loader.css": {productionLoaderCss, map[string]*bintree{}}, "logo.svg": {productionLogoSvg, map[string]*bintree{}}, "safari.png": {productionSafariPng, map[string]*bintree{}}, @@ -635,6 +635,6 @@ func assetFS() *assetfs.AssetFS { panic("unreachable") } -var UIReleaseTag = "RELEASE.2017-01-25T03-10-51Z" -var UICommitID = "d41dcb784b4a40639525c27841b9250c123dcb56" -var UIVersion = "2017-01-25T03:10:51Z" +var UIReleaseTag = "RELEASE.2017-02-15T22-41-23Z" +var UICommitID = "b50e5164ba49acf3de57eb0dd5a45f1cd31b3411" +var UIVersion = "2017-02-15T22:41:23Z" diff --git a/browser/yarn.lock b/browser/yarn.lock index 003765826..f6f193a78 100644 --- a/browser/yarn.lock +++ b/browser/yarn.lock @@ -694,6 +694,10 @@ babylon@^6.11.0, babylon@^6.15.0, babylon@^6.8.0: version "6.15.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" +babylon@6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" + backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -756,7 +760,7 @@ bluebird@^2.10.2, bluebird@^2.9.27: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" -bluebird@^3.4.7: +bluebird@^3.0.5, bluebird@^3.4.7: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" @@ -1086,6 +1090,13 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" +config-chain@~1.1.5: + version "1.1.11" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + connect-history-api-fallback@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" @@ -1462,6 +1473,15 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" +editorconfig@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.13.2.tgz#8e57926d9ee69ab6cb999f027c2171467acceb35" + dependencies: + bluebird "^3.0.5" + commander "^2.9.0" + lru-cache "^3.2.0" + sigmund "^1.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1571,6 +1591,10 @@ escape-string-regexp@^1.0.2, escape-string-regexp@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" +esformatter-ignore@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/esformatter-ignore/-/esformatter-ignore-0.1.3.tgz#04d3b875bfa49dde004cc58df6f6bbc3c0567f1e" + esformatter-jsx-ignore@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/esformatter-jsx-ignore/-/esformatter-jsx-ignore-1.0.6.tgz#e594f6b77db6f85d8c1179ae6dc465756d422489" @@ -1578,6 +1602,15 @@ esformatter-jsx-ignore@^1.0.6: esprima-fb "^12001.1.0-dev-harmony-fb" fresh-falafel "^0.2.6" +esformatter-jsx@^7.4.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/esformatter-jsx/-/esformatter-jsx-7.4.1.tgz#b2209ae0908f413a747b1205727cbf4ba4249602" + dependencies: + babylon "6.14.1" + esformatter-ignore "^0.1.3" + extend "3.0.0" + js-beautify "1.6.4" + esformatter-parser@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/esformatter-parser/-/esformatter-parser-1.0.0.tgz#0854072d0487539ed39cae38d8a5432c17ec11d3" @@ -2200,7 +2233,7 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@~1.3.0: +ini@^1.3.4, ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" @@ -2428,6 +2461,15 @@ js-base64@^2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" +js-beautify@1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.6.4.tgz#a9af79699742ac9a1b6fddc1fdbc78bc4d515fc3" + dependencies: + config-chain "~1.1.5" + editorconfig "^0.13.2" + mkdirp "~0.5.0" + nopt "~3.0.1" + js-tokens@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.0.tgz#a2f2a969caae142fb3cd56228358c89366957bd1" @@ -2684,6 +2726,12 @@ lower-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.3.tgz#c92393d976793eee5ba4edb583cf8eae35bd9bfb" +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + dependencies: + pseudomap "^1.0.1" + lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" @@ -2902,7 +2950,7 @@ node-pre-gyp@^0.6.29: tar "~2.2.1" tar-pack "~3.3.0" -nopt@~3.0.6: +nopt@~3.0.1, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: @@ -3447,6 +3495,10 @@ promise@^7.0.3, promise@^7.1.1: dependencies: asap "~2.0.3" +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + protochain@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/protochain/-/protochain-1.0.5.tgz#991c407e99de264aadf8f81504b5e7faf7bfa260" @@ -3462,6 +3514,10 @@ prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -3609,6 +3665,10 @@ react-dropzone@^3.5.3: dependencies: attr-accept "^1.0.3" +react-infinite-scroller@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/react-infinite-scroller/-/react-infinite-scroller-1.0.6.tgz#bb406d70032d09fa9e4a3e2175d3adbf4a3f559d" + react-onclickout@2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/react-onclickout/-/react-onclickout-2.0.4.tgz#2c7539a647e1dcdcab0b28e2f4eae3c3e00f0c64" @@ -4039,7 +4099,7 @@ shelljs@^0.7.0: interpret "^1.0.0" rechoir "^0.6.2" -sigmund@~1.0.0: +sigmund@^1.0.1, sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" diff --git a/buildscripts/checkdeps.sh b/buildscripts/checkdeps.sh index 057f17b9d..b83fdfa43 100644 --- a/buildscripts/checkdeps.sh +++ b/buildscripts/checkdeps.sh @@ -97,7 +97,7 @@ assert_is_supported_arch() { assert_is_supported_os() { case "${KNAME}" in - Linux | FreeBSD ) + Linux | FreeBSD | OpenBSD | NetBSD | DragonFly ) return ;; Darwin ) @@ -113,7 +113,7 @@ assert_is_supported_os() { *) echo "ERROR" echo "OS '${KNAME}' is not supported." - echo "Supported OS: [Linux, FreeBSD, Darwin]" + echo "Supported OS: [Linux, FreeBSD, OpenBSD, NetBSD, Darwin, DragonFly]" exit 1 esac } diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index b83f49652..016db0a24 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -19,7 +19,6 @@ package cmd import ( "encoding/json" "encoding/xml" - "fmt" "io/ioutil" "net/http" "net/url" @@ -36,14 +35,14 @@ type mgmtQueryKey string // Only valid query params for list/clear locks management APIs. const ( - mgmtBucket mgmtQueryKey = "bucket" - mgmtObject mgmtQueryKey = "object" - mgmtPrefix mgmtQueryKey = "prefix" - mgmtOlderThan mgmtQueryKey = "older-than" - mgmtDelimiter mgmtQueryKey = "delimiter" - mgmtMarker mgmtQueryKey = "marker" - mgmtMaxKey mgmtQueryKey = "max-key" - mgmtDryRun mgmtQueryKey = "dry-run" + mgmtBucket mgmtQueryKey = "bucket" + mgmtObject mgmtQueryKey = "object" + mgmtPrefix mgmtQueryKey = "prefix" + mgmtLockDuration mgmtQueryKey = "duration" + mgmtDelimiter mgmtQueryKey = "delimiter" + mgmtMarker mgmtQueryKey = "marker" + mgmtMaxKey mgmtQueryKey = "max-key" + mgmtDryRun mgmtQueryKey = "dry-run" ) // ServerVersion - server version @@ -54,8 +53,8 @@ type ServerVersion struct { // ServerStatus - contains the response of service status API type ServerStatus struct { - StorageInfo StorageInfo `json:"storageInfo"` ServerVersion ServerVersion `json:"serverVersion"` + Uptime time.Duration `json:"uptime"` } // ServiceStatusHandler - GET /?service @@ -70,15 +69,22 @@ func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r * return } - // Fetch storage backend information - storageInfo := newObjectLayerFn().StorageInfo() // Fetch server version serverVersion := ServerVersion{Version: Version, CommitID: CommitID} + // Fetch uptimes from all peers. This may fail to due to lack + // of read-quorum availability. + uptime, err := getPeerUptimes(globalAdminPeers) + if err != nil { + writeErrorResponse(w, toAPIErrorCode(err), r.URL) + errorIf(err, "Possibly failed to get uptime from majority of servers.") + return + } + // Create API response serverStatus := ServerStatus{ - StorageInfo: storageInfo, ServerVersion: serverVersion, + Uptime: uptime, } // Marshal API response @@ -131,8 +137,8 @@ func (adminAPI adminAPIHandlers) ServiceCredentialsHandler(w http.ResponseWriter } // Avoid setting new credentials when they are already passed - // by the environnement - if globalEnvAccessKey != "" || globalEnvSecretKey != "" { + // by the environment. + if globalIsEnvCreds { writeErrorResponse(w, ErrMethodNotAllowed, r.URL) return } @@ -154,24 +160,25 @@ func (adminAPI adminAPIHandlers) ServiceCredentialsHandler(w http.ResponseWriter } // Check passed credentials - cred, err := getCredential(req.Username, req.Password) - switch err { - case errInvalidAccessKeyLength: - writeErrorResponse(w, ErrAdminInvalidAccessKey, r.URL) - return - case errInvalidSecretKeyLength: - writeErrorResponse(w, ErrAdminInvalidSecretKey, r.URL) + err = validateAuthKeys(req.Username, req.Password) + if err != nil { + writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } + creds := credential{ + AccessKey: req.Username, + SecretKey: req.Password, + } + // Notify all other Minio peers to update credentials - updateErrs := updateCredsOnPeers(cred) + updateErrs := updateCredsOnPeers(creds) for peer, err := range updateErrs { errorIf(err, "Unable to update credentials on peer %s.", peer) } - // Update local credentials - serverConfig.SetCredential(cred) + // Update local credentials in memory. + serverConfig.SetCredential(creds) if err = serverConfig.Save(); err != nil { writeErrorResponse(w, ErrInternalError, r.URL) return @@ -181,11 +188,103 @@ func (adminAPI adminAPIHandlers) ServiceCredentialsHandler(w http.ResponseWriter w.WriteHeader(http.StatusOK) } +// ServerProperties holds some server information such as, version, region +// uptime, etc.. +type ServerProperties struct { + Uptime time.Duration `json:"uptime"` + Version string `json:"version"` + CommitID string `json:"commitID"` + Region string `json:"region"` + SQSARN []string `json:"sqsARN"` +} + +// ServerConnStats holds transferred bytes from/to the server +type ServerConnStats struct { + TotalInputBytes uint64 `json:"transferred"` + TotalOutputBytes uint64 `json:"received"` + Throughput uint64 `json:"throughput,omitempty"` +} + +// ServerInfo holds the information that will be returned by ServerInfo API +type ServerInfo struct { + StorageInfo StorageInfo `json:"storage"` + ConnStats ServerConnStats `json:"network"` + Properties ServerProperties `json:"server"` +} + +// ServerInfoHandler - GET /?server-info +// ---------- +// Get server information +func (adminAPI adminAPIHandlers) ServerInfoHandler(w http.ResponseWriter, r *http.Request) { + // Authenticate request + adminAPIErr := checkRequestAuthType(r, "", "", "") + if adminAPIErr != ErrNone { + writeErrorResponse(w, adminAPIErr, r.URL) + return + } + + // Build storage info + objLayer := newObjectLayerFn() + if objLayer == nil { + writeErrorResponse(w, ErrServerNotInitialized, r.URL) + return + } + storage := objLayer.StorageInfo() + + // Build list of enabled ARNs queues + var arns []string + for queueArn := range globalEventNotifier.GetAllExternalTargets() { + arns = append(arns, queueArn) + } + + // Fetch uptimes from all peers. This may fail to due to lack + // of read-quorum availability. + uptime, err := getPeerUptimes(globalAdminPeers) + if err != nil { + writeErrorResponse(w, toAPIErrorCode(err), r.URL) + errorIf(err, "Unable to get uptime from majority of servers.") + return + } + + // Build server properties information + properties := ServerProperties{ + Version: Version, + CommitID: CommitID, + Region: serverConfig.GetRegion(), + SQSARN: arns, + Uptime: uptime, + } + + // Build network info + connStats := ServerConnStats{ + TotalInputBytes: globalConnStats.getTotalInputBytes(), + TotalOutputBytes: globalConnStats.getTotalOutputBytes(), + } + + // Build the whole returned information + info := ServerInfo{ + StorageInfo: storage, + ConnStats: connStats, + Properties: properties, + } + + // Marshal API response + jsonBytes, err := json.Marshal(info) + if err != nil { + writeErrorResponse(w, ErrInternalError, r.URL) + errorIf(err, "Failed to marshal storage info into json.") + return + } + // Reply with storage information (across nodes in a + // distributed setup) as json. + writeSuccessResponseJSON(w, jsonBytes) +} + // validateLockQueryParams - Validates query params for list/clear locks management APIs. func validateLockQueryParams(vars url.Values) (string, string, time.Duration, APIErrorCode) { bucket := vars.Get(string(mgmtBucket)) prefix := vars.Get(string(mgmtPrefix)) - relTimeStr := vars.Get(string(mgmtOlderThan)) + durationStr := vars.Get(string(mgmtLockDuration)) // N B empty bucket name is invalid if !IsValidBucketName(bucket) { @@ -198,24 +297,24 @@ func validateLockQueryParams(vars url.Values) (string, string, time.Duration, AP // If older-than parameter was empty then set it to 0s to list // all locks older than now. - if relTimeStr == "" { - relTimeStr = "0s" + if durationStr == "" { + durationStr = "0s" } - relTime, err := time.ParseDuration(relTimeStr) + duration, err := time.ParseDuration(durationStr) if err != nil { errorIf(err, "Failed to parse duration passed as query value.") return "", "", time.Duration(0), ErrInvalidDuration } - return bucket, prefix, relTime, ErrNone + return bucket, prefix, duration, ErrNone } -// ListLocksHandler - GET /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time +// ListLocksHandler - GET /?lock&bucket=mybucket&prefix=myprefix&duration=duration // - bucket is a mandatory query parameter // - prefix and older-than are optional query parameters // HTTP header x-minio-operation: list // --------- -// Lists locks held on a given bucket, prefix and relative time. +// Lists locks held on a given bucket, prefix and duration it was held for. func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http.Request) { adminAPIErr := checkRequestAuthType(r, "", "", "") if adminAPIErr != ErrNone { @@ -224,15 +323,15 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http } vars := r.URL.Query() - bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars) + bucket, prefix, duration, adminAPIErr := validateLockQueryParams(vars) if adminAPIErr != ErrNone { writeErrorResponse(w, adminAPIErr, r.URL) return } // Fetch lock information of locks matching bucket/prefix that - // are available since relTime. - volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime) + // are available for longer than duration. + volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, duration) if err != nil { writeErrorResponse(w, ErrInternalError, r.URL) errorIf(err, "Failed to fetch lock information from remote nodes.") @@ -248,16 +347,16 @@ func (adminAPI adminAPIHandlers) ListLocksHandler(w http.ResponseWriter, r *http } // Reply with list of locks held on bucket, matching prefix - // older than relTime supplied, as json. + // held longer than duration supplied, as json. writeSuccessResponseJSON(w, jsonBytes) } -// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=relTime +// ClearLocksHandler - POST /?lock&bucket=mybucket&prefix=myprefix&duration=duration // - bucket is a mandatory query parameter // - prefix and older-than are optional query parameters // HTTP header x-minio-operation: clear // --------- -// Clear locks held on a given bucket, prefix and relative time. +// Clear locks held on a given bucket, prefix and duration it was held for. func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *http.Request) { adminAPIErr := checkRequestAuthType(r, "", "", "") if adminAPIErr != ErrNone { @@ -266,15 +365,15 @@ func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *htt } vars := r.URL.Query() - bucket, prefix, relTime, adminAPIErr := validateLockQueryParams(vars) + bucket, prefix, duration, adminAPIErr := validateLockQueryParams(vars) if adminAPIErr != ErrNone { writeErrorResponse(w, adminAPIErr, r.URL) return } // Fetch lock information of locks matching bucket/prefix that - // are available since relTime. - volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, relTime) + // are held for longer than duration. + volLocks, err := listPeerLocksInfo(globalAdminPeers, bucket, prefix, duration) if err != nil { writeErrorResponse(w, ErrInternalError, r.URL) errorIf(err, "Failed to fetch lock information from remote nodes.") @@ -289,7 +388,7 @@ func (adminAPI adminAPIHandlers) ClearLocksHandler(w http.ResponseWriter, r *htt return } - // Remove lock matching bucket/prefix older than relTime. + // Remove lock matching bucket/prefix held longer than duration. for _, volLock := range volLocks { globalNSMutex.ForceUnlock(volLock.Bucket, volLock.Object) } @@ -541,7 +640,6 @@ func (adminAPI adminAPIHandlers) HealFormatHandler(w http.ResponseWriter, r *htt // Create a new set of storage instances to heal format.json. bootstrapDisks, err := initStorageDisks(globalEndpoints) if err != nil { - fmt.Println(traceError(err)) writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } @@ -549,7 +647,6 @@ func (adminAPI adminAPIHandlers) HealFormatHandler(w http.ResponseWriter, r *htt // Heal format.json on available storage. err = healFormatXL(bootstrapDisks) if err != nil { - fmt.Println(traceError(err)) writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } @@ -557,7 +654,6 @@ func (adminAPI adminAPIHandlers) HealFormatHandler(w http.ResponseWriter, r *htt // Instantiate new object layer with newly formatted storage. newObjectAPI, err := newXLObjects(bootstrapDisks) if err != nil { - fmt.Println(traceError(err)) writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index 22c406d1e..e309e3f27 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -25,6 +25,7 @@ import ( "net/http/httptest" "net/url" "testing" + "time" router "github.com/gorilla/mux" ) @@ -43,6 +44,7 @@ type adminXLTestBed struct { func prepareAdminXLTestBed() (*adminXLTestBed, error) { // reset global variables to start afresh. resetTestGlobals() + // Initialize minio server config. rootPath, err := newTestConfig(globalMinioDefaultRegion) if err != nil { @@ -54,6 +56,9 @@ func prepareAdminXLTestBed() (*adminXLTestBed, error) { return nil, xlErr } + // Initialize boot time + globalBootTime = time.Now().UTC() + // Set globalEndpoints for a single node XL setup. for _, xlDir := range xlDirs { globalEndpoints = append(globalEndpoints, &url.URL{ @@ -197,7 +202,7 @@ func testServicesCmdHandler(cmd cmdType, t *testing.T) { // Initialize admin peers to make admin RPC calls. Note: In a // single node setup, this degenerates to a simple function // call under the hood. - eps, err := parseStorageEndpoints([]string{"http://localhost"}) + eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) if err != nil { t.Fatalf("Failed to parse storage end point - %v", err) } @@ -224,14 +229,13 @@ func testServicesCmdHandler(cmd cmdType, t *testing.T) { if cmd == statusCmd { expectedInfo := ServerStatus{ - StorageInfo: newObjectLayerFn().StorageInfo(), ServerVersion: ServerVersion{Version: Version, CommitID: CommitID}, } receivedInfo := ServerStatus{} if jsonErr := json.Unmarshal(rec.Body.Bytes(), &receivedInfo); jsonErr != nil { t.Errorf("Failed to unmarshal StorageInfo - %v", jsonErr) } - if expectedInfo != receivedInfo { + if expectedInfo.ServerVersion != receivedInfo.ServerVersion { t.Errorf("Expected storage info and received storage info differ, %v %v", expectedInfo, receivedInfo) } } @@ -264,7 +268,7 @@ func TestServiceSetCreds(t *testing.T) { // Initialize admin peers to make admin RPC calls. Note: In a // single node setup, this degenerates to a simple function // call under the hood. - eps, err := parseStorageEndpoints([]string{"http://localhost"}) + eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) if err != nil { t.Fatalf("Failed to parse storage end point - %v", err) } @@ -294,11 +298,9 @@ func TestServiceSetCreds(t *testing.T) { for i, testCase := range testCases { // Set or unset environement keys if !testCase.EnvKeysSet { - globalEnvAccessKey = "" - globalEnvSecretKey = "" + globalIsEnvCreds = false } else { - globalEnvAccessKey = testCase.Username - globalEnvSecretKey = testCase.Password + globalIsEnvCreds = true } // Construct setCreds request body @@ -336,12 +338,12 @@ func TestServiceSetCreds(t *testing.T) { } // mkLockQueryVal - helper function to build lock query param. -func mkLockQueryVal(bucket, prefix, relTimeStr string) url.Values { +func mkLockQueryVal(bucket, prefix, durationStr string) url.Values { qVal := url.Values{} qVal.Set("lock", "") qVal.Set(string(mgmtBucket), bucket) qVal.Set(string(mgmtPrefix), prefix) - qVal.Set(string(mgmtOlderThan), relTimeStr) + qVal.Set(string(mgmtLockDuration), durationStr) return qVal } @@ -354,7 +356,7 @@ func TestListLocksHandler(t *testing.T) { defer adminTestBed.TearDown() // Initialize admin peers to make admin RPC calls. - eps, err := parseStorageEndpoints([]string{"http://localhost"}) + eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) if err != nil { t.Fatalf("Failed to parse storage end point - %v", err) } @@ -366,41 +368,41 @@ func TestListLocksHandler(t *testing.T) { testCases := []struct { bucket string prefix string - relTime string + duration string expectedStatus int }{ // Test 1 - valid testcase { bucket: "mybucket", prefix: "myobject", - relTime: "1s", + duration: "1s", expectedStatus: http.StatusOK, }, // Test 2 - invalid duration { bucket: "mybucket", prefix: "myprefix", - relTime: "invalidDuration", + duration: "invalidDuration", expectedStatus: http.StatusBadRequest, }, // Test 3 - invalid bucket name { bucket: `invalid\\Bucket`, prefix: "myprefix", - relTime: "1h", + duration: "1h", expectedStatus: http.StatusBadRequest, }, // Test 4 - invalid prefix { bucket: "mybucket", prefix: `invalid\\Prefix`, - relTime: "1h", + duration: "1h", expectedStatus: http.StatusBadRequest, }, } for i, test := range testCases { - queryVal := mkLockQueryVal(test.bucket, test.prefix, test.relTime) + queryVal := mkLockQueryVal(test.bucket, test.prefix, test.duration) req, err := newTestRequest("GET", "/?"+queryVal.Encode(), 0, nil) if err != nil { t.Fatalf("Test %d - Failed to construct list locks request - %v", i+1, err) @@ -429,7 +431,7 @@ func TestClearLocksHandler(t *testing.T) { defer adminTestBed.TearDown() // Initialize admin peers to make admin RPC calls. - eps, err := parseStorageEndpoints([]string{"http://localhost"}) + eps, err := parseStorageEndpoints([]string{"http://127.0.0.1"}) if err != nil { t.Fatalf("Failed to parse storage end point - %v", err) } @@ -438,41 +440,41 @@ func TestClearLocksHandler(t *testing.T) { testCases := []struct { bucket string prefix string - relTime string + duration string expectedStatus int }{ // Test 1 - valid testcase { bucket: "mybucket", prefix: "myobject", - relTime: "1s", + duration: "1s", expectedStatus: http.StatusOK, }, // Test 2 - invalid duration { bucket: "mybucket", prefix: "myprefix", - relTime: "invalidDuration", + duration: "invalidDuration", expectedStatus: http.StatusBadRequest, }, // Test 3 - invalid bucket name { bucket: `invalid\\Bucket`, prefix: "myprefix", - relTime: "1h", + duration: "1h", expectedStatus: http.StatusBadRequest, }, // Test 4 - invalid prefix { bucket: "mybucket", prefix: `invalid\\Prefix`, - relTime: "1h", + duration: "1h", expectedStatus: http.StatusBadRequest, }, } for i, test := range testCases { - queryVal := mkLockQueryVal(test.bucket, test.prefix, test.relTime) + queryVal := mkLockQueryVal(test.bucket, test.prefix, test.duration) req, err := newTestRequest("POST", "/?"+queryVal.Encode(), 0, nil) if err != nil { t.Fatalf("Test %d - Failed to construct clear locks request - %v", i+1, err) diff --git a/cmd/admin-router.go b/cmd/admin-router.go index 3136670f6..b22794c97 100644 --- a/cmd/admin-router.go +++ b/cmd/admin-router.go @@ -39,6 +39,9 @@ func registerAdminRouter(mux *router.Router) { // Service update credentials adminRouter.Methods("POST").Queries("service", "").Headers(minioAdminOpHeader, "set-credentials").HandlerFunc(adminAPI.ServiceCredentialsHandler) + // Info operations + adminRouter.Methods("GET").Queries("info", "").HandlerFunc(adminAPI.ServerInfoHandler) + /// Lock operations // List Locks diff --git a/cmd/admin-rpc-client.go b/cmd/admin-rpc-client.go index 5f22e6177..6cb0709be 100644 --- a/cmd/admin-rpc-client.go +++ b/cmd/admin-rpc-client.go @@ -19,6 +19,7 @@ package cmd import ( "net/url" "path" + "sort" "sync" "time" ) @@ -37,8 +38,9 @@ type remoteAdminClient struct { // commands like service stop and service restart. type adminCmdRunner interface { Restart() error - ListLocks(bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) + ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) ReInitDisks() error + Uptime() (time.Duration, error) } // Restart - Sends a message over channel to the go-routine @@ -49,8 +51,8 @@ func (lc localAdminClient) Restart() error { } // ListLocks - Fetches lock information from local lock instrumentation. -func (lc localAdminClient) ListLocks(bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) { - return listLocksInfo(bucket, prefix, relTime), nil +func (lc localAdminClient) ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) { + return listLocksInfo(bucket, prefix, duration), nil } // Restart - Sends restart command to remote server via RPC. @@ -61,11 +63,11 @@ func (rc remoteAdminClient) Restart() error { } // ListLocks - Sends list locks command to remote server via RPC. -func (rc remoteAdminClient) ListLocks(bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) { +func (rc remoteAdminClient) ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) { listArgs := ListLocksQuery{ - bucket: bucket, - prefix: prefix, - relTime: relTime, + bucket: bucket, + prefix: prefix, + duration: duration, } var reply ListLocksReply if err := rc.Call("Admin.ListLocks", &listArgs, &reply); err != nil { @@ -88,6 +90,28 @@ func (rc remoteAdminClient) ReInitDisks() error { return rc.Call("Admin.ReInitDisks", &args, &reply) } +// Uptime - Returns the uptime of this server. Timestamp is taken +// after object layer is initialized. +func (lc localAdminClient) Uptime() (time.Duration, error) { + if globalBootTime.IsZero() { + return time.Duration(0), errServerNotInitialized + } + + return time.Now().UTC().Sub(globalBootTime), nil +} + +// Uptime - returns the uptime of the server to which the RPC call is made. +func (rc remoteAdminClient) Uptime() (time.Duration, error) { + args := AuthRPCArgs{} + reply := UptimeReply{} + err := rc.Call("Admin.Uptime", &args, &reply) + if err != nil { + return time.Duration(0), err + } + + return reply.Uptime, nil +} + // adminPeer - represents an entity that implements Restart methods. type adminPeer struct { addr string @@ -175,8 +199,8 @@ func sendServiceCmd(cps adminPeers, cmd serviceSignal) { } // listPeerLocksInfo - fetch list of locks held on the given bucket, -// matching prefix older than relTime from all peer servers. -func listPeerLocksInfo(peers adminPeers, bucket, prefix string, relTime time.Duration) ([]VolumeLockInfo, error) { +// matching prefix held longer than duration from all peer servers. +func listPeerLocksInfo(peers adminPeers, bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) { // Used to aggregate volume lock information from all nodes. allLocks := make([][]VolumeLockInfo, len(peers)) errs := make([]error, len(peers)) @@ -188,11 +212,11 @@ func listPeerLocksInfo(peers adminPeers, bucket, prefix string, relTime time.Dur go func(idx int, remotePeer adminPeer) { defer wg.Done() // `remotePeers` is right-shifted by one position relative to `peers` - allLocks[idx], errs[idx] = remotePeer.cmdRunner.ListLocks(bucket, prefix, relTime) + allLocks[idx], errs[idx] = remotePeer.cmdRunner.ListLocks(bucket, prefix, duration) }(i+1, remotePeer) } wg.Wait() - allLocks[0], errs[0] = localPeer.cmdRunner.ListLocks(bucket, prefix, relTime) + allLocks[0], errs[0] = localPeer.cmdRunner.ListLocks(bucket, prefix, duration) // Summarizing errors received for ListLocks RPC across all // nodes. N B the possible unavailability of quorum in errors @@ -241,3 +265,74 @@ func reInitPeerDisks(peers adminPeers) error { wg.Wait() return nil } + +// uptimeSlice - used to sort uptimes in chronological order. +type uptimeSlice []struct { + err error + uptime time.Duration +} + +func (ts uptimeSlice) Len() int { + return len(ts) +} + +func (ts uptimeSlice) Less(i, j int) bool { + return ts[i].uptime < ts[j].uptime +} + +func (ts uptimeSlice) Swap(i, j int) { + ts[i], ts[j] = ts[j], ts[i] +} + +// getPeerUptimes - returns the uptime since the last time read quorum +// was established on success. Otherwise returns errXLReadQuorum. +func getPeerUptimes(peers adminPeers) (time.Duration, error) { + // In a single node Erasure or FS backend setup the uptime of + // the setup is the uptime of the single minio server + // instance. + if !globalIsDistXL { + return time.Now().UTC().Sub(globalBootTime), nil + } + + uptimes := make(uptimeSlice, len(peers)) + + // Get up time of all servers. + wg := sync.WaitGroup{} + for i, peer := range peers { + wg.Add(1) + go func(idx int, peer adminPeer) { + defer wg.Done() + uptimes[idx].uptime, uptimes[idx].err = peer.cmdRunner.Uptime() + }(i, peer) + } + wg.Wait() + + // Sort uptimes in chronological order. + sort.Sort(uptimes) + + // Pick the readQuorum'th uptime in chronological order. i.e, + // the time at which read quorum was (re-)established. + readQuorum := len(uptimes) / 2 + validCount := 0 + latestUptime := time.Duration(0) + for _, uptime := range uptimes { + if uptime.err != nil { + errorIf(uptime.err, "Unable to fetch uptime") + continue + } + + validCount++ + if validCount >= readQuorum { + latestUptime = uptime.uptime + break + } + } + + // Less than readQuorum "Admin.Uptime" RPC call returned + // successfully, so read-quorum unavailable. + if validCount < readQuorum { + return time.Duration(0), InsufficientReadQuorum{} + } + + return latestUptime, nil +} diff --git a/cmd/admin-rpc-server.go b/cmd/admin-rpc-server.go index 470082fde..d5f8178bd 100644 --- a/cmd/admin-rpc-server.go +++ b/cmd/admin-rpc-server.go @@ -37,9 +37,9 @@ type adminCmd struct { // ListLocksQuery - wraps ListLocks API's query values to send over RPC. type ListLocksQuery struct { AuthRPCArgs - bucket string - prefix string - relTime time.Duration + bucket string + prefix string + duration time.Duration } // ListLocksReply - wraps ListLocks response over RPC. @@ -48,6 +48,12 @@ type ListLocksReply struct { volLocks []VolumeLockInfo } +// UptimeReply - wraps the uptime response over RPC. +type UptimeReply struct { + AuthRPCReply + Uptime time.Duration +} + // Restart - Restart this instance of minio server. func (s *adminCmd) Restart(args *AuthRPCArgs, reply *AuthRPCReply) error { if err := args.IsAuthenticated(); err != nil { @@ -63,7 +69,7 @@ func (s *adminCmd) ListLocks(query *ListLocksQuery, reply *ListLocksReply) error if err := query.IsAuthenticated(); err != nil { return err } - volLocks := listLocksInfo(query.bucket, query.prefix, query.relTime) + volLocks := listLocksInfo(query.bucket, query.prefix, query.duration) *reply = ListLocksReply{volLocks: volLocks} return nil } @@ -105,6 +111,27 @@ func (s *adminCmd) ReInitDisks(args *AuthRPCArgs, reply *AuthRPCReply) error { return nil } +// Uptime - returns the time when object layer was initialized on this server. +func (s *adminCmd) Uptime(args *AuthRPCArgs, reply *UptimeReply) error { + if err := args.IsAuthenticated(); err != nil { + return err + } + + if globalBootTime.IsZero() { + return errServerNotInitialized + } + + // N B The uptime is computed assuming that the system time is + // monotonic. This is not the case in time pkg in Go, see + // https://github.com/golang/go/issues/12914. This is expected + // to be fixed by go1.9. + *reply = UptimeReply{ + Uptime: time.Now().UTC().Sub(globalBootTime), + } + + return nil +} + // registerAdminRPCRouter - registers RPC methods for service status, // stop and restart commands. func registerAdminRPCRouter(mux *router.Router) error { diff --git a/cmd/api-errors.go b/cmd/api-errors.go index 8021b8098..8eb82761a 100644 --- a/cmd/api-errors.go +++ b/cmd/api-errors.go @@ -83,6 +83,7 @@ const ( ErrInvalidPartOrder ErrAuthorizationHeaderMalformed ErrMalformedPOSTRequest + ErrPOSTFileRequired ErrSignatureVersionNotSupported ErrBucketNotEmpty ErrAllAccessDisabled @@ -333,6 +334,11 @@ var errorCodeResponse = map[APIErrorCode]APIError{ Description: "The body of your POST request is not well-formed multipart/form-data.", HTTPStatusCode: http.StatusBadRequest, }, + ErrPOSTFileRequired: { + Code: "InvalidArgument", + Description: "POST requires exactly one file upload per request.", + HTTPStatusCode: http.StatusBadRequest, + }, ErrSignatureVersionNotSupported: { Code: "InvalidRequest", Description: "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.", @@ -483,7 +489,7 @@ var errorCodeResponse = map[APIErrorCode]APIError{ }, ErrInvalidDuration: { Code: "InvalidDuration", - Description: "Relative duration provided in the request is invalid.", + Description: "Duration provided in the request is invalid.", HTTPStatusCode: http.StatusBadRequest, }, @@ -606,6 +612,14 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) { apiErr = ErrSignatureDoesNotMatch case errContentSHA256Mismatch: apiErr = ErrContentSHA256Mismatch + case errDataTooLarge: + apiErr = ErrEntityTooLarge + case errDataTooSmall: + apiErr = ErrEntityTooSmall + case errInvalidAccessKeyLength: + apiErr = ErrAdminInvalidAccessKey + case errInvalidSecretKeyLength: + apiErr = ErrAdminInvalidSecretKey } if apiErr != ErrNone { diff --git a/cmd/api-response.go b/cmd/api-response.go index 447a1e732..7f0641bb2 100644 --- a/cmd/api-response.go +++ b/cmd/api-response.go @@ -208,6 +208,13 @@ type CopyObjectResponse struct { ETag string // md5sum of the copied object. } +// CopyObjectPartResponse container returns ETag and LastModified of the successfully copied object +type CopyObjectPartResponse struct { + XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyPartResult" json:"-"` + LastModified string // time string of format "2006-01-02T15:04:05.000Z" + ETag string // md5sum of the copied object part. +} + // Initiator inherit from Owner struct, fields are same type Initiator Owner @@ -399,6 +406,14 @@ func generateCopyObjectResponse(etag string, lastModified time.Time) CopyObjectR } } +// generates CopyObjectPartResponse from etag and lastModified time. +func generateCopyObjectPartResponse(etag string, lastModified time.Time) CopyObjectPartResponse { + return CopyObjectPartResponse{ + ETag: "\"" + etag + "\"", + LastModified: lastModified.UTC().Format(timeFormatAMZLong), + } +} + // generates InitiateMultipartUploadResponse for given bucket, key and uploadID. func generateInitiateMultipartUploadResponse(bucket, key, uploadID string) InitiateMultipartUploadResponse { return InitiateMultipartUploadResponse{ diff --git a/cmd/api-router.go b/cmd/api-router.go index d92aaaa06..b9c76f772 100644 --- a/cmd/api-router.go +++ b/cmd/api-router.go @@ -40,6 +40,8 @@ func registerAPIRouter(mux *router.Router) { // HeadObject bucket.Methods("HEAD").Path("/{object:.+}").HandlerFunc(api.HeadObjectHandler) + // CopyObjectPart + bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(api.CopyObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") // PutObjectPart bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") // ListObjectPxarts diff --git a/cmd/auth-handler.go b/cmd/auth-handler.go index a50219d59..a48989f12 100644 --- a/cmd/auth-handler.go +++ b/cmd/auth-handler.go @@ -125,7 +125,8 @@ func checkRequestAuthType(r *http.Request, bucket, policyAction, region string) if reqAuthType == authTypeAnonymous && policyAction != "" { // http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html - return enforceBucketPolicy(bucket, policyAction, r.URL) + return enforceBucketPolicy(bucket, policyAction, r.URL.Path, + r.Referer(), r.URL.Query()) } // By default return ErrAccessDenied diff --git a/cmd/auth-handler_test.go b/cmd/auth-handler_test.go index de9d8e124..fbb78d4e2 100644 --- a/cmd/auth-handler_test.go +++ b/cmd/auth-handler_test.go @@ -36,7 +36,7 @@ func TestGetRequestAuthType(t *testing.T) { { req: &http.Request{ URL: &url.URL{ - Host: "localhost:9000", + Host: "127.0.0.1:9000", Scheme: httpScheme, Path: "/", }, @@ -53,7 +53,7 @@ func TestGetRequestAuthType(t *testing.T) { { req: &http.Request{ URL: &url.URL{ - Host: "localhost:9000", + Host: "127.0.0.1:9000", Scheme: httpScheme, Path: "/", }, @@ -68,7 +68,7 @@ func TestGetRequestAuthType(t *testing.T) { { req: &http.Request{ URL: &url.URL{ - Host: "localhost:9000", + Host: "127.0.0.1:9000", Scheme: httpScheme, Path: "/", }, @@ -83,7 +83,7 @@ func TestGetRequestAuthType(t *testing.T) { { req: &http.Request{ URL: &url.URL{ - Host: "localhost:9000", + Host: "127.0.0.1:9000", Scheme: httpScheme, Path: "/", RawQuery: "X-Amz-Credential=EXAMPLEINVALIDEXAMPL%2Fs3%2F20160314%2Fus-east-1", @@ -96,7 +96,7 @@ func TestGetRequestAuthType(t *testing.T) { { req: &http.Request{ URL: &url.URL{ - Host: "localhost:9000", + Host: "127.0.0.1:9000", Scheme: httpScheme, Path: "/", }, @@ -315,7 +315,8 @@ func TestIsReqAuthenticated(t *testing.T) { } defer removeAll(path) - serverConfig.SetCredential(credential{"myuser", "mypassword"}) + creds := newCredentialWithKeys("myuser", "mypassword") + serverConfig.SetCredential(creds) // List of test cases for validating http request authentication. testCases := []struct { @@ -325,11 +326,11 @@ func TestIsReqAuthenticated(t *testing.T) { // When request is nil, internal error is returned. {nil, ErrInternalError}, // When request is unsigned, access denied is returned. - {mustNewRequest("GET", "http://localhost:9000", 0, nil, t), ErrAccessDenied}, + {mustNewRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrAccessDenied}, // When request is properly signed, but has bad Content-MD5 header. - {mustNewSignedRequest("PUT", "http://localhost:9000", 5, bytes.NewReader([]byte("hello")), t), ErrBadDigest}, + {mustNewSignedRequest("PUT", "http://127.0.0.1:9000", 5, bytes.NewReader([]byte("hello")), t), ErrBadDigest}, // When request is properly signed, error is none. - {mustNewSignedRequest("GET", "http://localhost:9000", 0, nil, t), ErrNone}, + {mustNewSignedRequest("GET", "http://127.0.0.1:9000", 0, nil, t), ErrNone}, } // Validates all testcases. diff --git a/cmd/auth-rpc-client.go b/cmd/auth-rpc-client.go index 0df2f5286..74c7815b6 100644 --- a/cmd/auth-rpc-client.go +++ b/cmd/auth-rpc-client.go @@ -35,6 +35,19 @@ type authConfig struct { secureConn bool // Make TLS connection to RPC server or not. serviceName string // Service name of auth server. disableReconnect bool // Disable reconnect on failure or not. + + /// Retry configurable values. + + // Each retry unit multiplicative, measured in time.Duration. + // This is the basic unit used for calculating backoffs. + retryUnit time.Duration + // Maximum retry duration i.e A caller would wait no more than this + // duration to continue their loop. + retryCap time.Duration + + // Maximum retries an call authRPC client would do for a failed + // RPC call. + retryAttemptThreshold int } // AuthRPCClient is a authenticated RPC client which does authentication before doing Call(). @@ -47,6 +60,18 @@ type AuthRPCClient struct { // newAuthRPCClient - returns a JWT based authenticated (go) rpc client, which does automatic reconnect. func newAuthRPCClient(config authConfig) *AuthRPCClient { + // Check if retry params are set properly if not default them. + emptyDuration := time.Duration(int64(0)) + if config.retryUnit == emptyDuration { + config.retryUnit = defaultRetryUnit + } + if config.retryCap == emptyDuration { + config.retryCap = defaultRetryCap + } + if config.retryAttemptThreshold == 0 { + config.retryAttemptThreshold = globalAuthRPCRetryThreshold + } + return &AuthRPCClient{ rpcClient: newRPCClient(config.serverAddr, config.serviceEndpoint, config.secureConn), config: config, @@ -105,9 +130,13 @@ func (authClient *AuthRPCClient) Call(serviceMethod string, args interface { SetAuthToken(authToken string) SetRequestTime(requestTime time.Time) }, reply interface{}) (err error) { + + // Done channel is used to close any lingering retry routine, as soon + // as this function returns. doneCh := make(chan struct{}) defer close(doneCh) - for i := range newRetryTimer(time.Second, 30*time.Second, MaxJitter, doneCh) { + + for i := range newRetryTimer(authClient.config.retryUnit, authClient.config.retryCap, doneCh) { if err = authClient.call(serviceMethod, args, reply); err == rpc.ErrShutdown { // As connection at server side is closed, close the rpc client. authClient.Close() @@ -115,7 +144,7 @@ func (authClient *AuthRPCClient) Call(serviceMethod string, args interface { // Retry if reconnect is not disabled. if !authClient.config.disableReconnect { // Retry until threshold reaches. - if i < globalAuthRPCRetryThreshold { + if i < authClient.config.retryAttemptThreshold { continue } } diff --git a/cmd/benchmark-utils_test.go b/cmd/benchmark-utils_test.go index 079fd0cfb..bcd231568 100644 --- a/cmd/benchmark-utils_test.go +++ b/cmd/benchmark-utils_test.go @@ -133,11 +133,12 @@ func runPutObjectPartBenchmark(b *testing.B, obj ObjectLayer, partSize int) { } metadata := make(map[string]string) metadata["md5Sum"] = getMD5Hash([]byte(textPartData)) - md5Sum, err = obj.PutObjectPart(bucket, object, uploadID, j, int64(len(textPartData)), bytes.NewBuffer(textPartData), metadata["md5Sum"], sha256sum) + var partInfo PartInfo + partInfo, err = obj.PutObjectPart(bucket, object, uploadID, j, int64(len(textPartData)), bytes.NewBuffer(textPartData), metadata["md5Sum"], sha256sum) if err != nil { b.Fatal(err) } - if md5Sum != metadata["md5Sum"] { + if partInfo.ETag != metadata["md5Sum"] { b.Fatalf("Write no: %d: Md5Sum mismatch during object write into the bucket: Expected %s, got %s", i+1, md5Sum, metadata["md5Sum"]) } } diff --git a/cmd/browser-peer-rpc.go b/cmd/browser-peer-rpc.go index 79f9e7b53..398b907bf 100644 --- a/cmd/browser-peer-rpc.go +++ b/cmd/browser-peer-rpc.go @@ -63,6 +63,10 @@ func (br *browserPeerAPIHandlers) SetAuthPeer(args SetAuthPeerArgs, reply *AuthR return err } + if err := validateAuthKeys(args.Creds.AccessKey, args.Creds.SecretKey); err != nil { + return err + } + // Update credentials in memory serverConfig.SetCredential(args.Creds) diff --git a/cmd/bucket-handlers-listobjects.go b/cmd/bucket-handlers-listobjects.go index 81db8b65c..6381ce837 100644 --- a/cmd/bucket-handlers-listobjects.go +++ b/cmd/bucket-handlers-listobjects.go @@ -18,7 +18,6 @@ package cmd import ( "net/http" - "strings" "github.com/gorilla/mux" ) @@ -44,7 +43,7 @@ func validateListObjectsArgs(prefix, marker, delimiter string, maxKeys int) APIE // Marker is set validate pre-condition. if marker != "" { // Marker not common with prefix is not implemented. - if !strings.HasPrefix(marker, prefix) { + if !hasPrefix(marker, prefix) { return ErrNotImplemented } } diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 95227f4af..96a6971c0 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -33,7 +33,7 @@ import ( // http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html // Enforces bucket policies for a bucket for a given tatusaction. -func enforceBucketPolicy(bucket string, action string, reqURL *url.URL) (s3Error APIErrorCode) { +func enforceBucketPolicy(bucket, action, resource, referer string, queryParams url.Values) (s3Error APIErrorCode) { // Verify if bucket actually exists if err := checkBucketExist(bucket, newObjectLayerFn()); err != nil { err = errorCause(err) @@ -57,16 +57,21 @@ func enforceBucketPolicy(bucket string, action string, reqURL *url.URL) (s3Error } // Construct resource in 'arn:aws:s3:::examplebucket/object' format. - resource := bucketARNPrefix + strings.TrimSuffix(strings.TrimPrefix(reqURL.Path, "/"), "/") + arn := bucketARNPrefix + strings.TrimSuffix(strings.TrimPrefix(resource, "/"), "/") // Get conditions for policy verification. conditionKeyMap := make(map[string]set.StringSet) - for queryParam := range reqURL.Query() { - conditionKeyMap[queryParam] = set.CreateStringSet(reqURL.Query().Get(queryParam)) + for queryParam := range queryParams { + conditionKeyMap[queryParam] = set.CreateStringSet(queryParams.Get(queryParam)) + } + + // Add request referer to conditionKeyMap if present. + if referer != "" { + conditionKeyMap["referer"] = set.CreateStringSet(referer) } // Validate action, resource and conditions with current policy statements. - if !bucketPolicyEvalStatements(action, resource, conditionKeyMap, policy.Statements) { + if !bucketPolicyEvalStatements(action, arn, conditionKeyMap, policy.Statements) { return ErrAccessDenied } return ErrNone @@ -160,7 +165,7 @@ func (api objectAPIHandlers) ListMultipartUploadsHandler(w http.ResponseWriter, } if keyMarker != "" { // Marker not common with prefix is not implemented. - if !strings.HasPrefix(keyMarker, prefix) { + if !hasPrefix(keyMarker, prefix) { writeErrorResponse(w, ErrNotImplemented, r.URL) return } @@ -388,6 +393,13 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h return } + // Require Content-Length to be set in the request + size := r.ContentLength + if size < 0 { + writeErrorResponse(w, ErrMissingContentLength, r.URL) + return + } + // Here the parameter is the size of the form data that should // be loaded in memory, the remaining being put in temporary files. reader, err := r.MultipartReader() @@ -397,12 +409,34 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h return } - fileBody, fileName, formValues, err := extractPostPolicyFormValues(reader) + // Read multipart data and save in memory and in the disk if needed + form, err := reader.ReadForm(maxFormMemory) + if err != nil { + errorIf(err, "Unable to initialize multipart reader.") + writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL) + return + } + + // Remove all tmp files creating during multipart upload + defer form.RemoveAll() + + // Extract all form fields + fileBody, fileName, fileSize, formValues, err := extractPostPolicyFormValues(form) if err != nil { errorIf(err, "Unable to parse form values.") writeErrorResponse(w, ErrMalformedPOSTRequest, r.URL) return } + + // Check if file is provided, error out otherwise. + if fileBody == nil { + writeErrorResponse(w, ErrPOSTFileRequired, r.URL) + return + } + + // Close multipart file + defer fileBody.Close() + bucket := mux.Vars(r)["bucket"] formValues["Bucket"] = bucket @@ -438,21 +472,20 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h return } - // Use rangeReader to ensure that object size is within expected range. + // Ensure that the object size is within expected range, also the file size + // should not exceed the maximum single Put size (5 GiB) lengthRange := postPolicyForm.Conditions.ContentLengthRange if lengthRange.Valid { - // If policy restricted the size of the object. - fileBody = &rangeReader{ - Reader: fileBody, - Min: lengthRange.Min, - Max: lengthRange.Max, + if fileSize < lengthRange.Min { + errorIf(err, "Unable to create object.") + writeErrorResponse(w, toAPIErrorCode(errDataTooSmall), r.URL) + return } - } else { - // Default values of min/max size of the object. - fileBody = &rangeReader{ - Reader: fileBody, - Min: 0, - Max: maxObjectSize, + + if fileSize > lengthRange.Max || fileSize > maxObjectSize { + errorIf(err, "Unable to create object.") + writeErrorResponse(w, toAPIErrorCode(errDataTooLarge), r.URL) + return } } @@ -465,7 +498,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h objectLock.Lock() defer objectLock.Unlock() - objInfo, err := objectAPI.PutObject(bucket, object, -1, fileBody, metadata, sha256sum) + objInfo, err := objectAPI.PutObject(bucket, object, fileSize, fileBody, metadata, sha256sum) if err != nil { errorIf(err, "Unable to create object.") writeErrorResponse(w, toAPIErrorCode(err), r.URL) diff --git a/cmd/bucket-notification-utils.go b/cmd/bucket-notification-utils.go index 2c0e735f5..8845c5cdb 100644 --- a/cmd/bucket-notification-utils.go +++ b/cmd/bucket-notification-utils.go @@ -133,27 +133,27 @@ func isValidQueueID(queueARN string) bool { // Is Queue identifier valid?. if isAMQPQueue(sqsARN) { // AMQP eueue. - amqpN := serverConfig.GetAMQPNotifyByID(sqsARN.AccountID) + amqpN := serverConfig.Notify.GetAMQPByID(sqsARN.AccountID) return amqpN.Enable && amqpN.URL != "" } else if isNATSQueue(sqsARN) { - natsN := serverConfig.GetNATSNotifyByID(sqsARN.AccountID) + natsN := serverConfig.Notify.GetNATSByID(sqsARN.AccountID) return natsN.Enable && natsN.Address != "" } else if isElasticQueue(sqsARN) { // Elastic queue. - elasticN := serverConfig.GetElasticSearchNotifyByID(sqsARN.AccountID) + elasticN := serverConfig.Notify.GetElasticSearchByID(sqsARN.AccountID) return elasticN.Enable && elasticN.URL != "" } else if isRedisQueue(sqsARN) { // Redis queue. - redisN := serverConfig.GetRedisNotifyByID(sqsARN.AccountID) + redisN := serverConfig.Notify.GetRedisByID(sqsARN.AccountID) return redisN.Enable && redisN.Addr != "" } else if isPostgreSQLQueue(sqsARN) { - pgN := serverConfig.GetPostgreSQLNotifyByID(sqsARN.AccountID) + pgN := serverConfig.Notify.GetPostgreSQLByID(sqsARN.AccountID) // Postgres can work with only default conn. info. return pgN.Enable } else if isKafkaQueue(sqsARN) { - kafkaN := serverConfig.GetKafkaNotifyByID(sqsARN.AccountID) + kafkaN := serverConfig.Notify.GetKafkaByID(sqsARN.AccountID) return (kafkaN.Enable && len(kafkaN.Brokers) > 0 && kafkaN.Topic != "") } else if isWebhookQueue(sqsARN) { - webhookN := serverConfig.GetWebhookNotifyByID(sqsARN.AccountID) + webhookN := serverConfig.Notify.GetWebhookByID(sqsARN.AccountID) return webhookN.Enable && webhookN.Endpoint != "" } return false diff --git a/cmd/bucket-policy-handlers.go b/cmd/bucket-policy-handlers.go index 7a525dd95..d68e2537f 100644 --- a/cmd/bucket-policy-handlers.go +++ b/cmd/bucket-policy-handlers.go @@ -21,6 +21,8 @@ import ( "io" "io/ioutil" "net/http" + "runtime" + "strings" humanize "github.com/dustin/go-humanize" mux "github.com/gorilla/mux" @@ -63,6 +65,10 @@ func bucketPolicyActionMatch(action string, statement policyStatement) bool { // Match function matches wild cards in 'pattern' for resource. func resourceMatch(pattern, resource string) bool { + if runtime.GOOS == "windows" { + // For windows specifically make sure we are case insensitive. + return wildcard.Match(strings.ToLower(pattern), strings.ToLower(resource)) + } return wildcard.Match(pattern, resource) } @@ -71,6 +77,10 @@ func actionMatch(pattern, action string) bool { return wildcard.MatchSimple(pattern, action) } +func refererMatch(pattern, referer string) bool { + return wildcard.MatchSimple(pattern, referer) +} + // Verify if given resource matches with policy statement. func bucketPolicyResourceMatch(resource string, statement policyStatement) bool { // the resource rule for object could contain "*" wild card. @@ -85,33 +95,74 @@ func bucketPolicyConditionMatch(conditions map[string]set.StringSet, statement p // Supports following conditions. // - StringEquals // - StringNotEquals + // - StringLike + // - StringNotLike // // Supported applicable condition keys for each conditions. // - s3:prefix // - s3:max-keys - var conditionMatches = true + // - s3:aws-Referer + + // The following loop evaluates the logical AND of all the + // conditions in the statement. Note: we can break out of the + // loop if and only if a condition evaluates to false. for condition, conditionKeyVal := range statement.Conditions { + prefixConditon := conditionKeyVal["s3:prefix"] + maxKeyCondition := conditionKeyVal["s3:max-keys"] if condition == "StringEquals" { - if !conditionKeyVal["s3:prefix"].Equals(conditions["prefix"]) { - conditionMatches = false - break + // If there is no condition with "s3:prefix" or "s3:max-keys" condition key + // then there is nothing to check condition against. + if !prefixConditon.IsEmpty() && !prefixConditon.Equals(conditions["prefix"]) { + return false } - if !conditionKeyVal["s3:max-keys"].Equals(conditions["max-keys"]) { - conditionMatches = false - break + if !maxKeyCondition.IsEmpty() && !maxKeyCondition.Equals(conditions["max-keys"]) { + return false } } else if condition == "StringNotEquals" { - if !conditionKeyVal["s3:prefix"].Equals(conditions["prefix"]) { - conditionMatches = false - break + // If there is no condition with "s3:prefix" or "s3:max-keys" condition key + // then there is nothing to check condition against. + if !prefixConditon.IsEmpty() && prefixConditon.Equals(conditions["prefix"]) { + return false } - if !conditionKeyVal["s3:max-keys"].Equals(conditions["max-keys"]) { - conditionMatches = false - break + if !maxKeyCondition.IsEmpty() && maxKeyCondition.Equals(conditions["max-keys"]) { + return false + } + } else if condition == "StringLike" { + awsReferers := conditionKeyVal["aws:Referer"] + // Skip empty condition, it is trivially satisfied. + if awsReferers.IsEmpty() { + continue + } + // wildcard match of referer in statement was not empty. + // StringLike has a match, i.e, condition evaluates to true. + refererFound := false + for referer := range conditions["referer"] { + if !awsReferers.FuncMatch(refererMatch, referer).IsEmpty() { + refererFound = true + break + } + } + // No matching referer found, so the condition is false. + if !refererFound { + return false + } + } else if condition == "StringNotLike" { + awsReferers := conditionKeyVal["aws:Referer"] + // Skip empty condition, it is trivially satisfied. + if awsReferers.IsEmpty() { + continue + } + // wildcard match of referer in statement was not empty. + // StringNotLike has a match, i.e, condition evaluates to false. + for referer := range conditions["referer"] { + if !awsReferers.FuncMatch(refererMatch, referer).IsEmpty() { + return false + } } } } - return conditionMatches + + return true } // PutBucketPolicyHandler - PUT Bucket policy diff --git a/cmd/bucket-policy-handlers_test.go b/cmd/bucket-policy-handlers_test.go index cfc690ef7..a8ad8a3e1 100644 --- a/cmd/bucket-policy-handlers_test.go +++ b/cmd/bucket-policy-handlers_test.go @@ -913,7 +913,7 @@ func TestBucketPolicyConditionMatch(t *testing.T) { statementCondition: getStatementWithCondition("StringNotEquals", "s3:prefix", "Asia/"), condition: getInnerMap("prefix", "Asia/"), - expectedMatch: true, + expectedMatch: false, }, // Test case - 6. // StringNotEquals condition doesn't match. @@ -922,7 +922,7 @@ func TestBucketPolicyConditionMatch(t *testing.T) { statementCondition: getStatementWithCondition("StringNotEquals", "s3:prefix", "Asia/"), condition: getInnerMap("prefix", "Africa/"), - expectedMatch: false, + expectedMatch: true, }, // Test case - 7. // StringNotEquals condition matches. @@ -931,7 +931,7 @@ func TestBucketPolicyConditionMatch(t *testing.T) { statementCondition: getStatementWithCondition("StringNotEquals", "s3:max-keys", "Asia/"), condition: getInnerMap("max-keys", "Asia/"), - expectedMatch: true, + expectedMatch: false, }, // Test case - 8. // StringNotEquals condition doesn't match. @@ -940,7 +940,35 @@ func TestBucketPolicyConditionMatch(t *testing.T) { statementCondition: getStatementWithCondition("StringNotEquals", "s3:max-keys", "Asia/"), condition: getInnerMap("max-keys", "Africa/"), - expectedMatch: false, + expectedMatch: true, + }, + // Test case - 9. + // StringLike condition matches. + { + statementCondition: getStatementWithCondition("StringLike", "aws:Referer", "http://www.example.com/"), + condition: getInnerMap("referer", "http://www.example.com/"), + expectedMatch: true, + }, + // Test case - 10. + // StringLike condition doesn't match. + { + statementCondition: getStatementWithCondition("StringLike", "aws:Referer", "http://www.example.com/"), + condition: getInnerMap("referer", "www.somethingelse.com"), + expectedMatch: false, + }, + // Test case - 11. + // StringNotLike condition evaluates to false. + { + statementCondition: getStatementWithCondition("StringNotLike", "aws:Referer", "http://www.example.com/"), + condition: getInnerMap("referer", "http://www.example.com/"), + expectedMatch: false, + }, + // Test case - 12. + // StringNotLike condition evaluates to true. + { + statementCondition: getStatementWithCondition("StringNotLike", "aws:Referer", "http://www.example.com/"), + condition: getInnerMap("referer", "http://somethingelse.com/"), + expectedMatch: true, }, } @@ -949,7 +977,8 @@ func TestBucketPolicyConditionMatch(t *testing.T) { // call the function under test and assert the result with the expected result. doesMatch := bucketPolicyConditionMatch(tc.condition, tc.statementCondition) if tc.expectedMatch != doesMatch { - t.Errorf("Expected the match to be `%v`; got `%v`.", tc.expectedMatch, doesMatch) + t.Errorf("Expected the match to be `%v`; got `%v` - %v %v.", + tc.expectedMatch, doesMatch, tc.condition, tc.statementCondition) } }) } diff --git a/cmd/bucket-policy-parser.go b/cmd/bucket-policy-parser.go index 1264a610c..5d98b8690 100644 --- a/cmd/bucket-policy-parser.go +++ b/cmd/bucket-policy-parser.go @@ -29,17 +29,22 @@ import ( "github.com/minio/minio-go/pkg/set" ) +var conditionKeyActionMap = map[string]set.StringSet{ + "s3:prefix": set.CreateStringSet("s3:ListBucket"), + "s3:max-keys": set.CreateStringSet("s3:ListBucket"), +} + // supportedActionMap - lists all the actions supported by minio. var supportedActionMap = set.CreateStringSet("*", "s3:*", "s3:GetObject", "s3:ListBucket", "s3:PutObject", "s3:GetBucketLocation", "s3:DeleteObject", "s3:AbortMultipartUpload", "s3:ListBucketMultipartUploads", "s3:ListMultipartUploadParts") // supported Conditions type. -var supportedConditionsType = set.CreateStringSet("StringEquals", "StringNotEquals") +var supportedConditionsType = set.CreateStringSet("StringEquals", "StringNotEquals", "StringLike", "StringNotLike") // Validate s3:prefix, s3:max-keys are present if not // supported keys for the conditions. -var supportedConditionsKey = set.CreateStringSet("s3:prefix", "s3:max-keys") +var supportedConditionsKey = set.CreateStringSet("s3:prefix", "s3:max-keys", "aws:Referer") // supportedEffectMap - supported effects. var supportedEffectMap = set.CreateStringSet("Allow", "Deny") @@ -106,12 +111,12 @@ func isValidResources(resources set.StringSet) (err error) { return err } for resource := range resources { - if !strings.HasPrefix(resource, bucketARNPrefix) { + if !hasPrefix(resource, bucketARNPrefix) { err = errors.New("Unsupported resource style found: ‘" + resource + "’, please validate your policy document") return err } resourceSuffix := strings.SplitAfter(resource, bucketARNPrefix)[1] - if len(resourceSuffix) == 0 || strings.HasPrefix(resourceSuffix, "/") { + if len(resourceSuffix) == 0 || hasPrefix(resourceSuffix, "/") { err = errors.New("Invalid resource style found: ‘" + resource + "’, please validate your policy document") return err } @@ -178,11 +183,12 @@ func isValidPrincipals(principal interface{}) (err error) { return nil } -// isValidConditions - are valid conditions. -func isValidConditions(conditions map[string]map[string]set.StringSet) (err error) { - // Verify conditions should be valid. - // Validate if stringEquals, stringNotEquals are present - // if not throw an error. +// isValidConditions - returns nil if the given conditions valid and +// corresponding error otherwise. +func isValidConditions(actions set.StringSet, conditions map[string]map[string]set.StringSet) (err error) { + // Verify conditions should be valid. Validate if only + // supported condition keys are present and return error + // otherwise. conditionKeyVal := make(map[string]set.StringSet) for conditionType := range conditions { if !supportedConditionsType.Contains(conditionType) { @@ -194,6 +200,15 @@ func isValidConditions(conditions map[string]map[string]set.StringSet) (err erro err = fmt.Errorf("Unsupported condition key '%s', please validate your policy document", conditionType) return err } + + compatibleActions := conditionKeyActionMap[key] + if !compatibleActions.IsEmpty() && + compatibleActions.Intersection(actions).IsEmpty() { + err = fmt.Errorf("Unsupported condition key %s for the given actions %s, "+ + "please validate your policy document", key, actions) + return err + } + conditionVal, ok := conditionKeyVal[key] if ok && !value.Intersection(conditionVal).IsEmpty() { err = fmt.Errorf("Ambigious condition values for key '%s', please validate your policy document", key) @@ -222,8 +237,8 @@ func resourcePrefix(resource string) string { } // checkBucketPolicyResources validates Resources in unmarshalled bucket policy structure. -// First valation of Resources done for given set of Actions. -// Later its validated for recursive Resources. +// - Resources are validated against the given set of Actions. +// - func checkBucketPolicyResources(bucket string, bucketPolicy *bucketPolicy) APIErrorCode { // Validate statements for special actions and collect resources // for others to validate nesting. @@ -267,7 +282,7 @@ func checkBucketPolicyResources(bucket string, bucketPolicy *bucketPolicy) APIEr // nesting. Reject such rules. for _, otherResource := range resources { // Common prefix reject such rules. - if strings.HasPrefix(otherResource, resource) { + if hasPrefix(otherResource, resource) { return ErrPolicyNesting } } @@ -317,7 +332,7 @@ func parseBucketPolicy(bucketPolicyReader io.Reader, policy *bucketPolicy) (err return err } // Statement conditions should be valid. - if err := isValidConditions(statement.Conditions); err != nil { + if err := isValidConditions(statement.Actions, statement.Conditions); err != nil { return err } } diff --git a/cmd/bucket-policy-parser_test.go b/cmd/bucket-policy-parser_test.go index 522dc2c63..a712a30c4 100644 --- a/cmd/bucket-policy-parser_test.go +++ b/cmd/bucket-policy-parser_test.go @@ -22,6 +22,7 @@ import ( "fmt" "testing" + "github.com/minio/minio-go/pkg/policy" "github.com/minio/minio-go/pkg/set" ) @@ -342,6 +343,18 @@ func TestIsValidPrincipals(t *testing.T) { } } +// getEmptyConditionKeyMap - returns a function that generates a +// condition key map for a given key. +func getEmptyConditionKeyMap(conditionKey string) func() map[string]map[string]set.StringSet { + emptyConditonGenerator := func() map[string]map[string]set.StringSet { + emptyMap := make(map[string]set.StringSet) + conditions := make(map[string]map[string]set.StringSet) + conditions[conditionKey] = emptyMap + return conditions + } + return emptyConditonGenerator +} + // Tests validate policyStatement condition validator. func TestIsValidConditions(t *testing.T) { // returns empty conditions map. @@ -350,22 +363,17 @@ func TestIsValidConditions(t *testing.T) { } // returns map with the "StringEquals" set to empty map. - setEmptyStringEquals := func() map[string]map[string]set.StringSet { - emptyMap := make(map[string]set.StringSet) - conditions := make(map[string]map[string]set.StringSet) - conditions["StringEquals"] = emptyMap - return conditions - - } + setEmptyStringEquals := getEmptyConditionKeyMap("StringEquals") // returns map with the "StringNotEquals" set to empty map. - setEmptyStringNotEquals := func() map[string]map[string]set.StringSet { - emptyMap := make(map[string]set.StringSet) - conditions := make(map[string]map[string]set.StringSet) - conditions["StringNotEquals"] = emptyMap - return conditions + setEmptyStringNotEquals := getEmptyConditionKeyMap("StringNotEquals") + + // returns map with the "StringLike" set to empty map. + setEmptyStringLike := getEmptyConditionKeyMap("StringLike") + + // returns map with the "StringNotLike" set to empty map. + setEmptyStringNotLike := getEmptyConditionKeyMap("StringNotLike") - } // Generate conditions. generateConditions := func(key1, key2, value string) map[string]map[string]set.StringSet { innerMap := make(map[string]set.StringSet) @@ -377,11 +385,11 @@ func TestIsValidConditions(t *testing.T) { // generate ambigious conditions. generateAmbigiousConditions := func() map[string]map[string]set.StringSet { - innerMap := make(map[string]set.StringSet) - innerMap["s3:prefix"] = set.CreateStringSet("Asia/") + prefixMap := make(map[string]set.StringSet) + prefixMap["s3:prefix"] = set.CreateStringSet("Asia/") conditions := make(map[string]map[string]set.StringSet) - conditions["StringEquals"] = innerMap - conditions["StringNotEquals"] = innerMap + conditions["StringEquals"] = prefixMap + conditions["StringNotEquals"] = prefixMap return conditions } @@ -417,13 +425,20 @@ func TestIsValidConditions(t *testing.T) { setEmptyConditions(), setEmptyStringEquals(), setEmptyStringNotEquals(), + setEmptyStringLike(), + setEmptyStringNotLike(), generateConditions("StringEquals", "s3:prefix", "Asia/"), generateConditions("StringEquals", "s3:max-keys", "100"), generateConditions("StringNotEquals", "s3:prefix", "Asia/"), generateConditions("StringNotEquals", "s3:max-keys", "100"), } + getObjectActionSet := set.CreateStringSet("s3:GetObject") + roBucketActionSet := set.CreateStringSet(readOnlyBucketActions...) + maxKeysConditionErr := fmt.Errorf("Unsupported condition key %s for the given actions %s, "+ + "please validate your policy document", "s3:max-keys", getObjectActionSet) testCases := []struct { + inputActions set.StringSet inputCondition map[string]map[string]set.StringSet // expected result. expectedErr error @@ -433,42 +448,44 @@ func TestIsValidConditions(t *testing.T) { // Malformed conditions. // Test case - 1. // "StringValues" is an invalid type. - {testConditions[0], fmt.Errorf("Unsupported condition type 'StringValues', " + + {roBucketActionSet, testConditions[0], fmt.Errorf("Unsupported condition type 'StringValues', " + "please validate your policy document"), false}, // Test case - 2. // "s3:Object" is an invalid key. - {testConditions[1], fmt.Errorf("Unsupported condition key " + + {roBucketActionSet, testConditions[1], fmt.Errorf("Unsupported condition key " + "'StringEquals', please validate your policy document"), false}, // Test case - 3. // Test case with Ambigious conditions set. - {testConditions[2], fmt.Errorf("Ambigious condition values for key 's3:prefix', " + + {roBucketActionSet, testConditions[2], fmt.Errorf("Ambigious condition values for key 's3:prefix', " + "please validate your policy document"), false}, // Test case - 4. // Test case with valid and invalid condition types. - {testConditions[3], fmt.Errorf("Unsupported condition type 'InvalidType', " + + {roBucketActionSet, testConditions[3], fmt.Errorf("Unsupported condition type 'InvalidType', " + "please validate your policy document"), false}, // Test case - 5. // Test case with valid and invalid condition keys. - {testConditions[4], fmt.Errorf("Unsupported condition key 'StringEquals', " + + {roBucketActionSet, testConditions[4], fmt.Errorf("Unsupported condition key 'StringEquals', " + "please validate your policy document"), false}, // Test cases with valid conditions. // Test case - 6. - {testConditions[5], nil, true}, + {roBucketActionSet, testConditions[5], nil, true}, // Test case - 7. - {testConditions[6], nil, true}, + {roBucketActionSet, testConditions[6], nil, true}, // Test case - 8. - {testConditions[7], nil, true}, + {roBucketActionSet, testConditions[7], nil, true}, // Test case - 9. - {testConditions[8], nil, true}, + {roBucketActionSet, testConditions[8], nil, true}, // Test case - 10. - {testConditions[9], nil, true}, + {roBucketActionSet, testConditions[9], nil, true}, // Test case - 11. - {testConditions[10], nil, true}, - // Test case 10. - {testConditions[11], nil, true}, + {roBucketActionSet, testConditions[10], nil, true}, + // Test case - 12. + {roBucketActionSet, testConditions[11], nil, true}, + // Test case - 13. + {getObjectActionSet, testConditions[11], maxKeysConditionErr, false}, } for i, testCase := range testCases { - actualErr := isValidConditions(testCase.inputCondition) + actualErr := isValidConditions(testCase.inputActions, testCase.inputCondition) if actualErr != nil && testCase.shouldPass { t.Errorf("Test %d: Expected to pass, but failed with: %s", i+1, actualErr.Error()) } @@ -709,3 +726,64 @@ func TestParseBucketPolicy(t *testing.T) { } } } + +func TestAWSRefererCondition(t *testing.T) { + resource := set.CreateStringSet([]string{ + fmt.Sprintf("%s%s", bucketARNPrefix, "minio-bucket"+"/"+"Asia"+"*"), + }...) + + conditionsKeyMap := make(policy.ConditionKeyMap) + conditionsKeyMap.Add("aws:Referer", + set.CreateStringSet("www.example.com", + "http://www.example.com")) + + requestConditionKeyMap := make(map[string]set.StringSet) + requestConditionKeyMap["referer"] = set.CreateStringSet("www.example.com") + + testCases := []struct { + effect string + conditionKey string + match bool + }{ + { + effect: "Allow", + conditionKey: "StringLike", + match: true, + }, + { + effect: "Allow", + conditionKey: "StringNotLike", + match: false, + }, + { + effect: "Deny", + conditionKey: "StringLike", + match: true, + }, + { + effect: "Deny", + conditionKey: "StringNotLike", + match: false, + }, + } + + for i, test := range testCases { + conditions := make(map[string]map[string]set.StringSet) + conditions[test.conditionKey] = conditionsKeyMap + + allowStatement := policyStatement{ + Sid: "Testing AWS referer condition", + Effect: test.effect, + Principal: map[string]interface{}{ + "AWS": "*", + }, + Resources: resource, + Conditions: conditions, + } + + if result := bucketPolicyConditionMatch(requestConditionKeyMap, allowStatement); result != test.match { + t.Errorf("Test %d - Expected conditons to evaluate to %v but got %v", + i+1, test.match, result) + } + } +} diff --git a/cmd/checkport.go b/cmd/checkport.go index 489adfba3..648868520 100644 --- a/cmd/checkport.go +++ b/cmd/checkport.go @@ -22,25 +22,13 @@ import ( "syscall" ) -// Make sure that none of the other processes are listening on the -// specified port on any of the interfaces. -// -// On linux if a process is listening on 127.0.0.1:9000 then Listen() -// on ":9000" fails with the error "port already in use". -// However on Mac OSX Listen() on ":9000" falls back to the IPv6 address. -// This causes confusion on Mac OSX that minio server is not reachable -// on 127.0.0.1 even though minio server is running. So before we start -// the minio server we make sure that the port is free on each tcp network. -// -// Port is string on purpose here. -// https://github.com/golang/go/issues/16142#issuecomment-245912773 -// -// "Keep in mind that ports in Go are strings: https://play.golang.org/p/zk2WEri_E9" -// - @bradfitz -func checkPortAvailability(portStr string) error { +// checkPortAvailability - check if given port is already in use. +// Note: The check method tries to listen on given port and closes it. +// It is possible to have a disconnected client in this tiny window of time. +func checkPortAvailability(port string) error { network := [3]string{"tcp", "tcp4", "tcp6"} for _, n := range network { - l, err := net.Listen(n, net.JoinHostPort("", portStr)) + l, err := net.Listen(n, net.JoinHostPort("", port)) if err != nil { if isAddrInUse(err) { // Return error if another process is listening on the diff --git a/cmd/commands.go b/cmd/commands.go index 96aa05ec0..b74f33f4a 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -16,13 +16,16 @@ package cmd -import "github.com/minio/cli" +import ( + "github.com/minio/cli" + "github.com/minio/minio/pkg/trie" +) // Collection of minio commands currently supported are. var commands = []cli.Command{} // Collection of minio commands currently supported in a trie tree. -var commandsTree = newTrie() +var commandsTree = trie.NewTrie() // registerCommand registers a cli command. func registerCommand(command cli.Command) { diff --git a/cmd/config-migrate.go b/cmd/config-migrate.go index f153f17ff..d6a07b045 100644 --- a/cmd/config-migrate.go +++ b/cmd/config-migrate.go @@ -855,7 +855,10 @@ func migrateV12ToV13() error { } // Copy over fields from V12 into V13 config struct - srvConfig := &serverConfigV13{} + srvConfig := &serverConfigV13{ + Logger: &logger{}, + Notify: ¬ifier{}, + } srvConfig.Version = "13" srvConfig.Credential = cv12.Credential srvConfig.Region = cv12.Region diff --git a/cmd/config-migrate_test.go b/cmd/config-migrate_test.go index c5b8a0827..b1fb6e24e 100644 --- a/cmd/config-migrate_test.go +++ b/cmd/config-migrate_test.go @@ -50,7 +50,7 @@ func TestServerConfigMigrateV1(t *testing.T) { } // Initialize server config and check again if everything is fine - if _, err := initConfig(); err != nil { + if err := loadConfig(credential{}); err != nil { t.Fatalf("Unable to initialize from updated config file %s", err) } } @@ -143,7 +143,7 @@ func TestServerConfigMigrateV2toV12(t *testing.T) { } // Initialize server config and check again if everything is fine - if _, err := initConfig(); err != nil { + if err := loadConfig(credential{}); err != nil { t.Fatalf("Unable to initialize from updated config file %s", err) } @@ -160,11 +160,6 @@ func TestServerConfigMigrateV2toV12(t *testing.T) { if serverConfig.Credential.SecretKey != secretKey { t.Fatalf("Secret key lost during migration, expected: %v, found: %v", secretKey, serverConfig.Credential.SecretKey) } - - // Initialize server config and check again if everything is fine - if _, err := initConfig(); err != nil { - t.Fatalf("Unable to initialize from updated config file %s", err) - } } // Test if all migrate code returns error with corrupted config files diff --git a/cmd/config-v13.go b/cmd/config-v13.go index 5ba8b78c6..f1ee32b90 100644 --- a/cmd/config-v13.go +++ b/cmd/config-v13.go @@ -36,75 +36,97 @@ type serverConfigV13 struct { Region string `json:"region"` // Additional error logging configuration. - Logger logger `json:"logger"` + Logger *logger `json:"logger"` // Notification queue configuration. - Notify notifier `json:"notify"` + Notify *notifier `json:"notify"` } -// initConfig - initialize server config and indicate if we are -// creating a new file or we are just loading -func initConfig() (bool, error) { - if !isConfigFileExists() { - // Initialize server config. - srvCfg := &serverConfigV13{} - srvCfg.Version = globalMinioConfigVersion - srvCfg.Region = globalMinioDefaultRegion - srvCfg.Credential = newCredential() - - // Enable console logger by default on a fresh run. - srvCfg.Logger.Console = consoleLogger{ - Enable: true, - Level: "error", - } - - // Make sure to initialize notification configs. - srvCfg.Notify.AMQP = make(map[string]amqpNotify) - srvCfg.Notify.AMQP["1"] = amqpNotify{} - srvCfg.Notify.ElasticSearch = make(map[string]elasticSearchNotify) - srvCfg.Notify.ElasticSearch["1"] = elasticSearchNotify{} - srvCfg.Notify.Redis = make(map[string]redisNotify) - srvCfg.Notify.Redis["1"] = redisNotify{} - srvCfg.Notify.NATS = make(map[string]natsNotify) - srvCfg.Notify.NATS["1"] = natsNotify{} - srvCfg.Notify.PostgreSQL = make(map[string]postgreSQLNotify) - srvCfg.Notify.PostgreSQL["1"] = postgreSQLNotify{} - srvCfg.Notify.Kafka = make(map[string]kafkaNotify) - srvCfg.Notify.Kafka["1"] = kafkaNotify{} - srvCfg.Notify.Webhook = make(map[string]webhookNotify) - srvCfg.Notify.Webhook["1"] = webhookNotify{} - - // Create config path. - err := createConfigPath() - if err != nil { - return false, err - } - - // hold the mutex lock before a new config is assigned. - // Save the new config globally. - // unlock the mutex. - serverConfigMu.Lock() - serverConfig = srvCfg - serverConfigMu.Unlock() - - // Save config into file. - return true, serverConfig.Save() +// newConfig - initialize a new server config, saves creds from env +// if globalIsEnvCreds is set otherwise generates a new set of keys +// and those are saved. +func newConfig(envCreds credential) error { + // Initialize server config. + srvCfg := &serverConfigV13{ + Logger: &logger{}, + Notify: ¬ifier{}, } + srvCfg.Version = globalMinioConfigVersion + srvCfg.Region = globalMinioDefaultRegion + + // If env is set for a fresh start, save them to config file. + if globalIsEnvCreds { + srvCfg.SetCredential(envCreds) + } else { + srvCfg.SetCredential(newCredential()) + } + + // Enable console logger by default on a fresh run. + srvCfg.Logger.Console = consoleLogger{ + Enable: true, + Level: "error", + } + + // Make sure to initialize notification configs. + srvCfg.Notify.AMQP = make(map[string]amqpNotify) + srvCfg.Notify.AMQP["1"] = amqpNotify{} + srvCfg.Notify.ElasticSearch = make(map[string]elasticSearchNotify) + srvCfg.Notify.ElasticSearch["1"] = elasticSearchNotify{} + srvCfg.Notify.Redis = make(map[string]redisNotify) + srvCfg.Notify.Redis["1"] = redisNotify{} + srvCfg.Notify.NATS = make(map[string]natsNotify) + srvCfg.Notify.NATS["1"] = natsNotify{} + srvCfg.Notify.PostgreSQL = make(map[string]postgreSQLNotify) + srvCfg.Notify.PostgreSQL["1"] = postgreSQLNotify{} + srvCfg.Notify.Kafka = make(map[string]kafkaNotify) + srvCfg.Notify.Kafka["1"] = kafkaNotify{} + srvCfg.Notify.Webhook = make(map[string]webhookNotify) + srvCfg.Notify.Webhook["1"] = webhookNotify{} + + // Create config path. + if err := createConfigPath(); err != nil { + return err + } + + // hold the mutex lock before a new config is assigned. + // Save the new config globally. + // unlock the mutex. + serverConfigMu.Lock() + serverConfig = srvCfg + serverConfigMu.Unlock() + + // Save config into file. + return serverConfig.Save() +} + +// loadConfig - loads a new config from disk, overrides creds from env +// if globalIsEnvCreds is set otherwise serves the creds from loaded +// from the disk. +func loadConfig(envCreds credential) error { configFile, err := getConfigFile() if err != nil { - return false, err + return err } + if _, err = os.Stat(configFile); err != nil { - return false, err + return err } srvCfg := &serverConfigV13{} srvCfg.Version = globalMinioConfigVersion qc, err := quick.New(srvCfg) if err != nil { - return false, err + return err } - if err := qc.Load(configFile); err != nil { - return false, err + + if err = qc.Load(configFile); err != nil { + return err + } + + // If env is set override the credentials from config file. + if globalIsEnvCreds { + srvCfg.SetCredential(envCreds) + } else { + srvCfg.SetCredential(srvCfg.Credential) } // hold the mutex lock before a new config is assigned. @@ -112,10 +134,10 @@ func initConfig() (bool, error) { // Save the loaded config globally. serverConfig = srvCfg serverConfigMu.Unlock() + // Set the version properly after the unmarshalled json is loaded. serverConfig.Version = globalMinioConfigVersion - - return false, nil + return nil } // serverConfig server config. @@ -129,193 +151,6 @@ func (s serverConfigV13) GetVersion() string { return s.Version } -/// Logger related. - -func (s *serverConfigV13) SetAMQPNotifyByID(accountID string, amqpn amqpNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.AMQP[accountID] = amqpn -} - -func (s serverConfigV13) GetAMQP() map[string]amqpNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.AMQP -} - -// GetAMQPNotify get current AMQP logger. -func (s serverConfigV13) GetAMQPNotifyByID(accountID string) amqpNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.AMQP[accountID] -} - -// -func (s *serverConfigV13) SetNATSNotifyByID(accountID string, natsn natsNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.NATS[accountID] = natsn -} - -func (s serverConfigV13) GetNATS() map[string]natsNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - return s.Notify.NATS -} - -// GetNATSNotify get current NATS logger. -func (s serverConfigV13) GetNATSNotifyByID(accountID string) natsNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.NATS[accountID] -} - -func (s *serverConfigV13) SetElasticSearchNotifyByID(accountID string, esNotify elasticSearchNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.ElasticSearch[accountID] = esNotify -} - -func (s serverConfigV13) GetElasticSearch() map[string]elasticSearchNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.ElasticSearch -} - -// GetElasticSearchNotify get current ElasicSearch logger. -func (s serverConfigV13) GetElasticSearchNotifyByID(accountID string) elasticSearchNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.ElasticSearch[accountID] -} - -func (s *serverConfigV13) SetRedisNotifyByID(accountID string, rNotify redisNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.Redis[accountID] = rNotify -} - -func (s serverConfigV13) GetRedis() map[string]redisNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.Redis -} - -func (s serverConfigV13) GetWebhook() map[string]webhookNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.Webhook -} - -// GetWebhookNotifyByID get current Webhook logger. -func (s serverConfigV13) GetWebhookNotifyByID(accountID string) webhookNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.Webhook[accountID] -} - -func (s *serverConfigV13) SetWebhookNotifyByID(accountID string, pgn webhookNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.Webhook[accountID] = pgn -} - -// GetRedisNotify get current Redis logger. -func (s serverConfigV13) GetRedisNotifyByID(accountID string) redisNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.Redis[accountID] -} - -func (s *serverConfigV13) SetPostgreSQLNotifyByID(accountID string, pgn postgreSQLNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.PostgreSQL[accountID] = pgn -} - -func (s serverConfigV13) GetPostgreSQL() map[string]postgreSQLNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.PostgreSQL -} - -func (s serverConfigV13) GetPostgreSQLNotifyByID(accountID string) postgreSQLNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.PostgreSQL[accountID] -} - -// Kafka related functions -func (s *serverConfigV13) SetKafkaNotifyByID(accountID string, kn kafkaNotify) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Notify.Kafka[accountID] = kn -} - -func (s serverConfigV13) GetKafka() map[string]kafkaNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.Kafka -} - -func (s serverConfigV13) GetKafkaNotifyByID(accountID string) kafkaNotify { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Notify.Kafka[accountID] -} - -// SetFileLogger set new file logger. -func (s *serverConfigV13) SetFileLogger(flogger fileLogger) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Logger.File = flogger -} - -// GetFileLogger get current file logger. -func (s serverConfigV13) GetFileLogger() fileLogger { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Logger.File -} - -// SetConsoleLogger set new console logger. -func (s *serverConfigV13) SetConsoleLogger(clogger consoleLogger) { - serverConfigMu.Lock() - defer serverConfigMu.Unlock() - - s.Logger.Console = clogger -} - -// GetConsoleLogger get current console logger. -func (s serverConfigV13) GetConsoleLogger() consoleLogger { - serverConfigMu.RLock() - defer serverConfigMu.RUnlock() - - return s.Logger.Console -} - // SetRegion set new region. func (s *serverConfigV13) SetRegion(region string) { serverConfigMu.Lock() @@ -337,7 +172,8 @@ func (s *serverConfigV13) SetCredential(creds credential) { serverConfigMu.Lock() defer serverConfigMu.Unlock() - s.Credential = creds + // Set updated credential. + s.Credential = newCredentialWithKeys(creds.AccessKey, creds.SecretKey) } // GetCredentials get current credentials. diff --git a/cmd/config-v13_test.go b/cmd/config-v13_test.go index 54312714e..4b4e420f9 100644 --- a/cmd/config-v13_test.go +++ b/cmd/config-v13_test.go @@ -40,57 +40,65 @@ func TestServerConfig(t *testing.T) { } // Set new amqp notification id. - serverConfig.SetAMQPNotifyByID("2", amqpNotify{}) - savedNotifyCfg1 := serverConfig.GetAMQPNotifyByID("2") + serverConfig.Notify.SetAMQPByID("2", amqpNotify{}) + savedNotifyCfg1 := serverConfig.Notify.GetAMQPByID("2") if !reflect.DeepEqual(savedNotifyCfg1, amqpNotify{}) { t.Errorf("Expecting AMQP config %#v found %#v", amqpNotify{}, savedNotifyCfg1) } // Set new elastic search notification id. - serverConfig.SetElasticSearchNotifyByID("2", elasticSearchNotify{}) - savedNotifyCfg2 := serverConfig.GetElasticSearchNotifyByID("2") + serverConfig.Notify.SetElasticSearchByID("2", elasticSearchNotify{}) + savedNotifyCfg2 := serverConfig.Notify.GetElasticSearchByID("2") if !reflect.DeepEqual(savedNotifyCfg2, elasticSearchNotify{}) { t.Errorf("Expecting Elasticsearch config %#v found %#v", elasticSearchNotify{}, savedNotifyCfg2) } // Set new redis notification id. - serverConfig.SetRedisNotifyByID("2", redisNotify{}) - savedNotifyCfg3 := serverConfig.GetRedisNotifyByID("2") + serverConfig.Notify.SetRedisByID("2", redisNotify{}) + savedNotifyCfg3 := serverConfig.Notify.GetRedisByID("2") if !reflect.DeepEqual(savedNotifyCfg3, redisNotify{}) { t.Errorf("Expecting Redis config %#v found %#v", redisNotify{}, savedNotifyCfg3) } // Set new kafka notification id. - serverConfig.SetKafkaNotifyByID("2", kafkaNotify{}) - savedNotifyCfg4 := serverConfig.GetKafkaNotifyByID("2") + serverConfig.Notify.SetKafkaByID("2", kafkaNotify{}) + savedNotifyCfg4 := serverConfig.Notify.GetKafkaByID("2") if !reflect.DeepEqual(savedNotifyCfg4, kafkaNotify{}) { t.Errorf("Expecting Kafka config %#v found %#v", kafkaNotify{}, savedNotifyCfg4) } // Set new Webhook notification id. - serverConfig.SetWebhookNotifyByID("2", webhookNotify{}) - savedNotifyCfg5 := serverConfig.GetWebhookNotifyByID("2") + serverConfig.Notify.SetWebhookByID("2", webhookNotify{}) + savedNotifyCfg5 := serverConfig.Notify.GetWebhookByID("2") if !reflect.DeepEqual(savedNotifyCfg5, webhookNotify{}) { t.Errorf("Expecting Webhook config %#v found %#v", webhookNotify{}, savedNotifyCfg3) } // Set new console logger. - serverConfig.SetConsoleLogger(consoleLogger{ + serverConfig.Logger.SetConsole(consoleLogger{ Enable: true, }) - consoleCfg := serverConfig.GetConsoleLogger() + consoleCfg := serverConfig.Logger.GetConsole() if !reflect.DeepEqual(consoleCfg, consoleLogger{Enable: true}) { t.Errorf("Expecting console logger config %#v found %#v", consoleLogger{Enable: true}, consoleCfg) } + // Set new console logger. + serverConfig.Logger.SetConsole(consoleLogger{ + Enable: false, + }) // Set new file logger. - serverConfig.SetFileLogger(fileLogger{ + serverConfig.Logger.SetFile(fileLogger{ Enable: true, }) - fileCfg := serverConfig.GetFileLogger() + fileCfg := serverConfig.Logger.GetFile() if !reflect.DeepEqual(fileCfg, fileLogger{Enable: true}) { t.Errorf("Expecting file logger config %#v found %#v", fileLogger{Enable: true}, consoleCfg) } + // Set new file logger. + serverConfig.Logger.SetFile(fileLogger{ + Enable: false, + }) // Match version. if serverConfig.GetVersion() != globalMinioConfigVersion { @@ -106,7 +114,7 @@ func TestServerConfig(t *testing.T) { setGlobalConfigPath(rootPath) // Initialize server config. - if _, err := initConfig(); err != nil { + if err := loadConfig(credential{}); err != nil { t.Fatalf("Unable to initialize from updated config file %s", err) } } diff --git a/cmd/credential.go b/cmd/credential.go index 4d84c9301..c75049050 100644 --- a/cmd/credential.go +++ b/cmd/credential.go @@ -19,6 +19,11 @@ package cmd import ( "crypto/rand" "encoding/base64" + "os" + + "github.com/minio/mc/pkg/console" + + "golang.org/x/crypto/bcrypt" ) const ( @@ -34,7 +39,7 @@ const ( func mustGetAccessKey() string { keyBytes := make([]byte, accessKeyMaxLen) if _, err := rand.Read(keyBytes); err != nil { - panic(err) + console.Fatalf("Unable to generate access key. Err: %s.\n", err) } for i := 0; i < accessKeyMaxLen; i++ { @@ -47,7 +52,7 @@ func mustGetAccessKey() string { func mustGetSecretKey() string { keyBytes := make([]byte, secretKeyMaxLen) if _, err := rand.Read(keyBytes); err != nil { - panic(err) + console.Fatalf("Unable to generate secret key. Err: %s.\n", err) } return string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen]) @@ -65,22 +70,70 @@ func isSecretKeyValid(secretKey string) bool { // credential container for access and secret keys. type credential struct { - AccessKey string `json:"accessKey"` - SecretKey string `json:"secretKey"` + AccessKey string `json:"accessKey,omitempty"` + SecretKey string `json:"secretKey,omitempty"` + secretKeyHash []byte } +// Generate a bcrypt hashed key for input secret key. +func mustGetHashedSecretKey(secretKey string) []byte { + hashedSecretKey, err := bcrypt.GenerateFromPassword([]byte(secretKey), bcrypt.DefaultCost) + if err != nil { + console.Fatalf("Unable to generate secret hash for secret key. Err: %s.\n", err) + } + return hashedSecretKey +} + +// Initialize a new credential object func newCredential() credential { - return credential{mustGetAccessKey(), mustGetSecretKey()} + return newCredentialWithKeys(mustGetAccessKey(), mustGetSecretKey()) } -func getCredential(accessKey, secretKey string) (credential, error) { +func newCredentialWithKeys(accessKey, secretKey string) credential { + secretHash := mustGetHashedSecretKey(secretKey) + return credential{accessKey, secretKey, secretHash} +} + +// Validate incoming auth keys. +func validateAuthKeys(accessKey, secretKey string) error { + // Validate the env values before proceeding. if !isAccessKeyValid(accessKey) { - return credential{}, errInvalidAccessKeyLength + return errInvalidAccessKeyLength } - if !isSecretKeyValid(secretKey) { - return credential{}, errInvalidSecretKeyLength + return errInvalidSecretKeyLength + } + return nil +} + +// Variant of getCredentialFromEnv but upon error fails right here. +func mustGetCredentialFromEnv() credential { + creds, err := getCredentialFromEnv() + if err != nil { + console.Fatalf("Unable to load credentials from environment. Err: %s.\n", err) + } + return creds +} + +// Converts accessKey and secretKeys into credential object which +// contains bcrypt secret key hash for future validation. +func getCredentialFromEnv() (credential, error) { + // Fetch access keys from environment variables and update the config. + accessKey := os.Getenv("MINIO_ACCESS_KEY") + secretKey := os.Getenv("MINIO_SECRET_KEY") + + // Envs are set globally. + globalIsEnvCreds = accessKey != "" && secretKey != "" + + if globalIsEnvCreds { + // Validate the env values before proceeding. + if err := validateAuthKeys(accessKey, secretKey); err != nil { + return credential{}, err + } + + // Return credential object. + return newCredentialWithKeys(accessKey, secretKey), nil } - return credential{accessKey, secretKey}, nil + return credential{}, nil } diff --git a/cmd/erasure-createfile.go b/cmd/erasure-createfile.go index 18797ba5f..f95c0c18c 100644 --- a/cmd/erasure-createfile.go +++ b/cmd/erasure-createfile.go @@ -28,7 +28,7 @@ import ( // erasureCreateFile - writes an entire stream by erasure coding to // all the disks, writes also calculate individual block's checksum // for future bit-rot protection. -func erasureCreateFile(disks []StorageAPI, volume, path string, reader io.Reader, blockSize int64, dataBlocks int, parityBlocks int, algo string, writeQuorum int) (bytesWritten int64, checkSums []string, err error) { +func erasureCreateFile(disks []StorageAPI, volume, path string, reader io.Reader, allowEmpty bool, blockSize int64, dataBlocks int, parityBlocks int, algo string, writeQuorum int) (bytesWritten int64, checkSums []string, err error) { // Allocated blockSized buffer for reading from incoming stream. buf := make([]byte, blockSize) @@ -47,7 +47,7 @@ func erasureCreateFile(disks []StorageAPI, volume, path string, reader io.Reader // We have reached EOF on the first byte read, io.Reader // must be 0bytes, we don't need to erasure code // data. Will create a 0byte file instead. - if bytesWritten == 0 { + if bytesWritten == 0 && allowEmpty { blocks = make([][]byte, len(disks)) rErr = appendFile(disks, volume, path, blocks, hashWriters, writeQuorum) if rErr != nil { @@ -137,9 +137,5 @@ func appendFile(disks []StorageAPI, volume, path string, enBlocks [][]byte, hash // Wait for all the appends to finish. wg.Wait() - // Do we have write quorum?. - if !isDiskQuorum(wErrs, writeQuorum) { - return traceError(errXLWriteQuorum) - } return reduceWriteQuorumErrs(wErrs, objectOpIgnoredErrs, writeQuorum) } diff --git a/cmd/erasure-createfile_test.go b/cmd/erasure-createfile_test.go index 2411bd432..bcc9973eb 100644 --- a/cmd/erasure-createfile_test.go +++ b/cmd/erasure-createfile_test.go @@ -56,7 +56,7 @@ func TestErasureCreateFile(t *testing.T) { t.Fatal(err) } // Test when all disks are up. - size, _, err := erasureCreateFile(disks, "testbucket", "testobject1", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, _, err := erasureCreateFile(disks, "testbucket", "testobject1", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } @@ -69,7 +69,7 @@ func TestErasureCreateFile(t *testing.T) { disks[5] = AppendDiskDown{disks[5].(*posix)} // Test when two disks are down. - size, _, err = erasureCreateFile(disks, "testbucket", "testobject2", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, _, err = erasureCreateFile(disks, "testbucket", "testobject2", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } @@ -83,7 +83,7 @@ func TestErasureCreateFile(t *testing.T) { disks[8] = AppendDiskDown{disks[8].(*posix)} disks[9] = AppendDiskDown{disks[9].(*posix)} - size, _, err = erasureCreateFile(disks, "testbucket", "testobject3", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, _, err = erasureCreateFile(disks, "testbucket", "testobject3", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } @@ -93,7 +93,7 @@ func TestErasureCreateFile(t *testing.T) { // 1 more disk down. 7 disk down in total. Should return quorum error. disks[10] = AppendDiskDown{disks[10].(*posix)} - _, _, err = erasureCreateFile(disks, "testbucket", "testobject4", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + _, _, err = erasureCreateFile(disks, "testbucket", "testobject4", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if errorCause(err) != errXLWriteQuorum { t.Errorf("erasureCreateFile return value: expected errXLWriteQuorum, got %s", err) } diff --git a/cmd/erasure-healfile_test.go b/cmd/erasure-healfile_test.go index b4e644c07..0f820738c 100644 --- a/cmd/erasure-healfile_test.go +++ b/cmd/erasure-healfile_test.go @@ -48,7 +48,7 @@ func TestErasureHealFile(t *testing.T) { t.Fatal(err) } // Create a test file. - size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject1", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject1", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } diff --git a/cmd/erasure-readfile_test.go b/cmd/erasure-readfile_test.go index ab0e8f947..51071952f 100644 --- a/cmd/erasure-readfile_test.go +++ b/cmd/erasure-readfile_test.go @@ -271,7 +271,7 @@ func TestErasureReadFileDiskFail(t *testing.T) { } // Create a test file to read from. - size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } @@ -354,7 +354,7 @@ func TestErasureReadFileOffsetLength(t *testing.T) { } // Create a test file to read from. - size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } @@ -433,7 +433,7 @@ func TestErasureReadFileRandomOffsetLength(t *testing.T) { iterations := 10000 // Create a test file to read from. - size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject", bytes.NewReader(data), blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) + size, checkSums, err := erasureCreateFile(disks, "testbucket", "testobject", bytes.NewReader(data), true, blockSize, dataBlocks, parityBlocks, bitRotAlgo, dataBlocks+1) if err != nil { t.Fatal(err) } diff --git a/cmd/erasure-utils.go b/cmd/erasure-utils.go index d01ea731a..814df1c47 100644 --- a/cmd/erasure-utils.go +++ b/cmd/erasure-utils.go @@ -24,8 +24,8 @@ import ( "sync" "github.com/klauspost/reedsolomon" - "github.com/minio/blake2b-simd" "github.com/minio/sha256-simd" + "golang.org/x/crypto/blake2b" ) // newHashWriters - inititialize a slice of hashes for the disk count. @@ -48,14 +48,14 @@ func newHash(algo string) (h hash.Hash) { // ignore the error, because New512 without a key never fails // New512 only returns a non-nil error, if the length of the passed // key > 64 bytes - but we use blake2b as hash function (no key) - h = blake2b.New512() + h, _ = blake2b.New512(nil) // Add new hashes here. default: // Default to blake2b. // ignore the error, because New512 without a key never fails // New512 only returns a non-nil error, if the length of the passed // key > 64 bytes - but we use blake2b as hash function (no key) - h = blake2b.New512() + h, _ = blake2b.New512(nil) } return h } diff --git a/cmd/event-notifier.go b/cmd/event-notifier.go index fa3eb5b7b..9db12cccf 100644 --- a/cmd/event-notifier.go +++ b/cmd/event-notifier.go @@ -162,9 +162,22 @@ func newNotificationEvent(event eventData) NotificationEvent { return nEvent } -// Fetch the external target. No locking needed here since this map is -// never written after initial startup. +// Fetch all external targets. This returns a copy of the current map of +// external notification targets. +func (en eventNotifier) GetAllExternalTargets() map[string]*logrus.Logger { + en.external.rwMutex.RLock() + defer en.external.rwMutex.RUnlock() + targetsCopy := make(map[string]*logrus.Logger) + for k, v := range en.external.targets { + targetsCopy[k] = v + } + return targetsCopy +} + +// Fetch the external target. func (en eventNotifier) GetExternalTarget(queueARN string) *logrus.Logger { + en.external.rwMutex.RLock() + defer en.external.rwMutex.RUnlock() return en.external.targets[queueARN] } @@ -531,7 +544,7 @@ func loadAllBucketNotifications(objAPI ObjectLayer) (map[string]*notificationCon func loadAllQueueTargets() (map[string]*logrus.Logger, error) { queueTargets := make(map[string]*logrus.Logger) // Load all amqp targets, initialize their respective loggers. - for accountID, amqpN := range serverConfig.GetAMQP() { + for accountID, amqpN := range serverConfig.Notify.GetAMQP() { if !amqpN.Enable { continue } @@ -558,7 +571,7 @@ func loadAllQueueTargets() (map[string]*logrus.Logger, error) { queueTargets[queueARN] = amqpLog } // Load all nats targets, initialize their respective loggers. - for accountID, natsN := range serverConfig.GetNATS() { + for accountID, natsN := range serverConfig.Notify.GetNATS() { if !natsN.Enable { continue } @@ -586,7 +599,7 @@ func loadAllQueueTargets() (map[string]*logrus.Logger, error) { } // Load redis targets, initialize their respective loggers. - for accountID, redisN := range serverConfig.GetRedis() { + for accountID, redisN := range serverConfig.Notify.GetRedis() { if !redisN.Enable { continue } @@ -614,7 +627,7 @@ func loadAllQueueTargets() (map[string]*logrus.Logger, error) { } // Load Webhook targets, initialize their respective loggers. - for accountID, webhookN := range serverConfig.GetWebhook() { + for accountID, webhookN := range serverConfig.Notify.GetWebhook() { if !webhookN.Enable { continue } @@ -635,7 +648,7 @@ func loadAllQueueTargets() (map[string]*logrus.Logger, error) { } // Load elastic targets, initialize their respective loggers. - for accountID, elasticN := range serverConfig.GetElasticSearch() { + for accountID, elasticN := range serverConfig.Notify.GetElasticSearch() { if !elasticN.Enable { continue } @@ -661,7 +674,7 @@ func loadAllQueueTargets() (map[string]*logrus.Logger, error) { } // Load PostgreSQL targets, initialize their respective loggers. - for accountID, pgN := range serverConfig.GetPostgreSQL() { + for accountID, pgN := range serverConfig.Notify.GetPostgreSQL() { if !pgN.Enable { continue } @@ -686,7 +699,7 @@ func loadAllQueueTargets() (map[string]*logrus.Logger, error) { queueTargets[queueARN] = pgLog } // Load Kafka targets, initialize their respective loggers. - for accountID, kafkaN := range serverConfig.GetKafka() { + for accountID, kafkaN := range serverConfig.Notify.GetKafka() { if !kafkaN.Enable { continue } diff --git a/cmd/event-notifier_test.go b/cmd/event-notifier_test.go index 0b52f65da..415350c24 100644 --- a/cmd/event-notifier_test.go +++ b/cmd/event-notifier_test.go @@ -106,7 +106,7 @@ func TestInitEventNotifierWithPostgreSQL(t *testing.T) { t.Fatal("Unable to initialize FS backend.", err) } - serverConfig.SetPostgreSQLNotifyByID("1", postgreSQLNotify{Enable: true}) + serverConfig.Notify.SetPostgreSQLByID("1", postgreSQLNotify{Enable: true}) if err := initEventNotifier(fs); err == nil { t.Fatal("PostgreSQL config didn't fail.") } @@ -137,7 +137,7 @@ func TestInitEventNotifierWithNATS(t *testing.T) { t.Fatal("Unable to initialize FS backend.", err) } - serverConfig.SetNATSNotifyByID("1", natsNotify{Enable: true}) + serverConfig.Notify.SetNATSByID("1", natsNotify{Enable: true}) if err := initEventNotifier(fs); err == nil { t.Fatal("NATS config didn't fail.") } @@ -168,7 +168,7 @@ func TestInitEventNotifierWithWebHook(t *testing.T) { t.Fatal("Unable to initialize FS backend.", err) } - serverConfig.SetWebhookNotifyByID("1", webhookNotify{Enable: true}) + serverConfig.Notify.SetWebhookByID("1", webhookNotify{Enable: true}) if err := initEventNotifier(fs); err == nil { t.Fatal("WebHook config didn't fail.") } @@ -199,7 +199,7 @@ func TestInitEventNotifierWithAMQP(t *testing.T) { t.Fatal("Unable to initialize FS backend.", err) } - serverConfig.SetAMQPNotifyByID("1", amqpNotify{Enable: true}) + serverConfig.Notify.SetAMQPByID("1", amqpNotify{Enable: true}) if err := initEventNotifier(fs); err == nil { t.Fatal("AMQP config didn't fail.") } @@ -230,7 +230,7 @@ func TestInitEventNotifierWithElasticSearch(t *testing.T) { t.Fatal("Unable to initialize FS backend.", err) } - serverConfig.SetElasticSearchNotifyByID("1", elasticSearchNotify{Enable: true}) + serverConfig.Notify.SetElasticSearchByID("1", elasticSearchNotify{Enable: true}) if err := initEventNotifier(fs); err == nil { t.Fatal("ElasticSearch config didn't fail.") } @@ -261,7 +261,7 @@ func TestInitEventNotifierWithRedis(t *testing.T) { t.Fatal("Unable to initialize FS backend.", err) } - serverConfig.SetRedisNotifyByID("1", redisNotify{Enable: true}) + serverConfig.Notify.SetRedisByID("1", redisNotify{Enable: true}) if err := initEventNotifier(fs); err == nil { t.Fatal("Redis config didn't fail.") } diff --git a/cmd/fs-v1-helpers.go b/cmd/fs-v1-helpers.go index 4c911380c..a64ad4c71 100644 --- a/cmd/fs-v1-helpers.go +++ b/cmd/fs-v1-helpers.go @@ -27,20 +27,20 @@ import ( // windows automatically. func fsRemoveFile(filePath string) (err error) { if filePath == "" { - return errInvalidArgument + return traceError(errInvalidArgument) } if err = checkPathLength(filePath); err != nil { - return err + return traceError(err) } if err = os.Remove(preparePath(filePath)); err != nil { if os.IsNotExist(err) { - return errFileNotFound + return traceError(errFileNotFound) } else if os.IsPermission(err) { - return errFileAccessDenied + return traceError(errFileAccessDenied) } - return err + return traceError(err) } return nil @@ -50,43 +50,44 @@ func fsRemoveFile(filePath string) (err error) { // long paths for windows automatically. func fsRemoveAll(dirPath string) (err error) { if dirPath == "" { - return errInvalidArgument + return traceError(errInvalidArgument) } if err = checkPathLength(dirPath); err != nil { - return err + return traceError(err) } if err = removeAll(dirPath); err != nil { if os.IsPermission(err) { - return errVolumeAccessDenied + return traceError(errVolumeAccessDenied) } + return traceError(err) } - return err - + return nil } // Removes a directory only if its empty, handles long // paths for windows automatically. func fsRemoveDir(dirPath string) (err error) { if dirPath == "" { - return errInvalidArgument + return traceError(errInvalidArgument) } if err = checkPathLength(dirPath); err != nil { - return err + return traceError(err) } if err = os.Remove(preparePath(dirPath)); err != nil { if os.IsNotExist(err) { - return errVolumeNotFound + return traceError(errVolumeNotFound) } else if isSysErrNotEmpty(err) { - return errVolumeNotEmpty + return traceError(errVolumeNotEmpty) } + return traceError(err) } - return err + return nil } // Creates a new directory, parent dir should exist @@ -95,26 +96,27 @@ func fsRemoveDir(dirPath string) (err error) { // are handled automatically. func fsMkdir(dirPath string) (err error) { if dirPath == "" { - return errInvalidArgument + return traceError(errInvalidArgument) } if err = checkPathLength(dirPath); err != nil { - return err + return traceError(err) } if err = os.Mkdir(preparePath(dirPath), 0777); err != nil { if os.IsExist(err) { - return errVolumeExists + return traceError(errVolumeExists) } else if os.IsPermission(err) { - return errDiskAccessDenied + return traceError(errDiskAccessDenied) } else if isSysErrNotDir(err) { // File path cannot be verified since // one of the parents is a file. - return errDiskAccessDenied + return traceError(errDiskAccessDenied) } else if isSysErrPathNotFound(err) { // Add specific case for windows. - return errDiskAccessDenied + return traceError(errDiskAccessDenied) } + return traceError(err) } return nil @@ -124,24 +126,24 @@ func fsMkdir(dirPath string) (err error) { // attributes upon success. func fsStatDir(statDir string) (os.FileInfo, error) { if statDir == "" { - return nil, errInvalidArgument + return nil, traceError(errInvalidArgument) } if err := checkPathLength(statDir); err != nil { - return nil, err + return nil, traceError(err) } fi, err := os.Stat(preparePath(statDir)) if err != nil { if os.IsNotExist(err) { - return nil, errVolumeNotFound + return nil, traceError(errVolumeNotFound) } else if os.IsPermission(err) { - return nil, errVolumeAccessDenied + return nil, traceError(errVolumeAccessDenied) } - return nil, err + return nil, traceError(err) } if !fi.IsDir() { - return nil, errVolumeAccessDenied + return nil, traceError(errVolumeAccessDenied) } return fi, nil @@ -150,28 +152,28 @@ func fsStatDir(statDir string) (os.FileInfo, error) { // Lookup if file exists, returns file attributes upon success func fsStatFile(statFile string) (os.FileInfo, error) { if statFile == "" { - return nil, errInvalidArgument + return nil, traceError(errInvalidArgument) } if err := checkPathLength(statFile); err != nil { - return nil, err + return nil, traceError(err) } fi, err := os.Stat(preparePath(statFile)) if err != nil { if os.IsNotExist(err) { - return nil, errFileNotFound + return nil, traceError(errFileNotFound) } else if os.IsPermission(err) { - return nil, errFileAccessDenied + return nil, traceError(errFileAccessDenied) } else if isSysErrNotDir(err) { - return nil, errFileAccessDenied + return nil, traceError(errFileAccessDenied) } else if isSysErrPathNotFound(err) { - return nil, errFileNotFound + return nil, traceError(errFileNotFound) } - return nil, err + return nil, traceError(err) } if fi.IsDir() { - return nil, errFileNotFound + return nil, traceError(errFileNotFound) } return fi, nil } @@ -180,44 +182,44 @@ func fsStatFile(statFile string) (os.FileInfo, error) { // a readable stream and the size of the readable stream. func fsOpenFile(readPath string, offset int64) (io.ReadCloser, int64, error) { if readPath == "" || offset < 0 { - return nil, 0, errInvalidArgument + return nil, 0, traceError(errInvalidArgument) } if err := checkPathLength(readPath); err != nil { - return nil, 0, err + return nil, 0, traceError(err) } fr, err := os.Open(preparePath(readPath)) if err != nil { if os.IsNotExist(err) { - return nil, 0, errFileNotFound + return nil, 0, traceError(errFileNotFound) } else if os.IsPermission(err) { - return nil, 0, errFileAccessDenied + return nil, 0, traceError(errFileAccessDenied) } else if isSysErrNotDir(err) { // File path cannot be verified since one of the parents is a file. - return nil, 0, errFileAccessDenied + return nil, 0, traceError(errFileAccessDenied) } else if isSysErrPathNotFound(err) { // Add specific case for windows. - return nil, 0, errFileNotFound + return nil, 0, traceError(errFileNotFound) } - return nil, 0, err + return nil, 0, traceError(err) } // Stat to get the size of the file at path. st, err := fr.Stat() if err != nil { - return nil, 0, err + return nil, 0, traceError(err) } // Verify if its not a regular file, since subsequent Seek is undefined. if !st.Mode().IsRegular() { - return nil, 0, errIsNotRegular + return nil, 0, traceError(errIsNotRegular) } // Seek to the requested offset. if offset > 0 { _, err = fr.Seek(offset, os.SEEK_SET) if err != nil { - return nil, 0, err + return nil, 0, traceError(err) } } @@ -228,22 +230,22 @@ func fsOpenFile(readPath string, offset int64) (io.ReadCloser, int64, error) { // Creates a file and copies data from incoming reader. Staging buffer is used by io.CopyBuffer. func fsCreateFile(tempObjPath string, reader io.Reader, buf []byte, fallocSize int64) (int64, error) { if tempObjPath == "" || reader == nil || buf == nil { - return 0, errInvalidArgument + return 0, traceError(errInvalidArgument) } if err := checkPathLength(tempObjPath); err != nil { - return 0, err + return 0, traceError(err) } if err := mkdirAll(pathutil.Dir(tempObjPath), 0777); err != nil { - return 0, err + return 0, traceError(err) } writer, err := os.OpenFile(preparePath(tempObjPath), os.O_CREATE|os.O_WRONLY, 0666) if err != nil { // File path cannot be verified since one of the parents is a file. if isSysErrNotDir(err) { - return 0, errFileAccessDenied + return 0, traceError(errFileAccessDenied) } return 0, err } @@ -252,13 +254,13 @@ func fsCreateFile(tempObjPath string, reader io.Reader, buf []byte, fallocSize i // Fallocate only if the size is final object is known. if fallocSize > 0 { if err = fsFAllocate(int(writer.Fd()), 0, fallocSize); err != nil { - return 0, err + return 0, traceError(err) } } bytesWritten, err := io.CopyBuffer(writer, reader, buf) if err != nil { - return 0, err + return 0, traceError(err) } return bytesWritten, nil @@ -267,20 +269,20 @@ func fsCreateFile(tempObjPath string, reader io.Reader, buf []byte, fallocSize i // Removes uploadID at destination path. func fsRemoveUploadIDPath(basePath, uploadIDPath string) error { if basePath == "" || uploadIDPath == "" { - return errInvalidArgument + return traceError(errInvalidArgument) } // List all the entries in uploadID. entries, err := readDir(uploadIDPath) if err != nil && err != errFileNotFound { - return err + return traceError(err) } // Delete all the entries obtained from previous readdir. for _, entryPath := range entries { err = fsDeleteFile(basePath, pathJoin(uploadIDPath, entryPath)) if err != nil && err != errFileNotFound { - return err + return traceError(err) } } @@ -325,11 +327,11 @@ func fsRenameFile(sourcePath, destPath string) error { // this function additionally protects the basePath from being deleted. func fsDeleteFile(basePath, deletePath string) error { if err := checkPathLength(basePath); err != nil { - return err + return traceError(err) } if err := checkPathLength(deletePath); err != nil { - return err + return traceError(err) } if basePath == deletePath { @@ -340,11 +342,11 @@ func fsDeleteFile(basePath, deletePath string) error { pathSt, err := os.Stat(preparePath(deletePath)) if err != nil { if os.IsNotExist(err) { - return errFileNotFound + return traceError(errFileNotFound) } else if os.IsPermission(err) { - return errFileAccessDenied + return traceError(errFileAccessDenied) } - return err + return traceError(err) } if pathSt.IsDir() && !isDirEmpty(deletePath) { @@ -355,13 +357,13 @@ func fsDeleteFile(basePath, deletePath string) error { // Attempt to remove path. if err = os.Remove(preparePath(deletePath)); err != nil { if os.IsNotExist(err) { - return errFileNotFound + return traceError(errFileNotFound) } else if os.IsPermission(err) { - return errFileAccessDenied + return traceError(errFileAccessDenied) } else if isSysErrNotEmpty(err) { - return errVolumeNotEmpty + return traceError(errVolumeNotEmpty) } - return err + return traceError(err) } // Recursively go down the next path and delete again. diff --git a/cmd/fs-v1-helpers_test.go b/cmd/fs-v1-helpers_test.go index 67541f670..afaff8a80 100644 --- a/cmd/fs-v1-helpers_test.go +++ b/cmd/fs-v1-helpers_test.go @@ -31,11 +31,11 @@ func TestFSStats(t *testing.T) { // Setup test environment. - if err = fsMkdir(""); err != errInvalidArgument { + if err = fsMkdir(""); errorCause(err) != errInvalidArgument { t.Fatal("Unexpected error", err) } - if err = fsMkdir(pathJoin(path, "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")); err != errFileNameTooLong { + if err = fsMkdir(pathJoin(path, "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")); errorCause(err) != errFileNameTooLong { t.Fatal("Unexpected error", err) } @@ -51,7 +51,7 @@ func TestFSStats(t *testing.T) { // Seek back. reader.Seek(0, 0) - if err = fsMkdir(pathJoin(path, "success-vol", "success-file")); err != errVolumeExists { + if err = fsMkdir(pathJoin(path, "success-vol", "success-file")); errorCause(err) != errVolumeExists { t.Fatal("Unexpected error", err) } @@ -138,11 +138,11 @@ func TestFSStats(t *testing.T) { for i, testCase := range testCases { if testCase.srcPath != "" { - if _, err := fsStatFile(pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { + if _, err := fsStatFile(pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); errorCause(err) != testCase.expectedErr { t.Fatalf("TestPosix case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) } } else { - if _, err := fsStatDir(pathJoin(testCase.srcFSPath, testCase.srcVol)); err != testCase.expectedErr { + if _, err := fsStatDir(pathJoin(testCase.srcFSPath, testCase.srcVol)); errorCause(err) != testCase.expectedErr { t.Fatalf("TestPosix case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) } } @@ -161,11 +161,11 @@ func TestFSCreateAndOpen(t *testing.T) { t.Fatalf("Unable to create directory, %s", err) } - if _, err = fsCreateFile("", nil, nil, 0); err != errInvalidArgument { + if _, err = fsCreateFile("", nil, nil, 0); errorCause(err) != errInvalidArgument { t.Fatal("Unexpected error", err) } - if _, _, err = fsOpenFile("", -1); err != errInvalidArgument { + if _, _, err = fsOpenFile("", -1); errorCause(err) != errInvalidArgument { t.Fatal("Unexpected error", err) } @@ -200,17 +200,17 @@ func TestFSCreateAndOpen(t *testing.T) { for i, testCase := range testCases { _, err = fsCreateFile(pathJoin(path, testCase.srcVol, testCase.srcPath), reader, buf, reader.Size()) - if err != testCase.expectedErr { + if errorCause(err) != testCase.expectedErr { t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) } _, _, err = fsOpenFile(pathJoin(path, testCase.srcVol, testCase.srcPath), 0) - if err != testCase.expectedErr { + if errorCause(err) != testCase.expectedErr { t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) } } // Attempt to open a directory. - if _, _, err = fsOpenFile(pathJoin(path), 0); err != errIsNotRegular { + if _, _, err = fsOpenFile(pathJoin(path), 0); errorCause(err) != errIsNotRegular { t.Fatal("Unexpected error", err) } } @@ -272,7 +272,7 @@ func TestFSDeletes(t *testing.T) { } for i, testCase := range testCases { - if err = fsDeleteFile(path, pathJoin(path, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { + if err = fsDeleteFile(path, pathJoin(path, testCase.srcVol, testCase.srcPath)); errorCause(err) != testCase.expectedErr { t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) } } @@ -374,11 +374,11 @@ func TestFSRemoves(t *testing.T) { for i, testCase := range testCases { if testCase.srcPath != "" { - if err = fsRemoveFile(pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { + if err = fsRemoveFile(pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); errorCause(err) != testCase.expectedErr { t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) } } else { - if err = fsRemoveDir(pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { + if err = fsRemoveDir(pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); errorCause(err) != testCase.expectedErr { t.Error(err) } } @@ -388,11 +388,11 @@ func TestFSRemoves(t *testing.T) { t.Fatal(err) } - if err = fsRemoveAll(""); err != errInvalidArgument { + if err = fsRemoveAll(""); errorCause(err) != errInvalidArgument { t.Fatal(err) } - if err = fsRemoveAll("my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); err != errFileNameTooLong { + if err = fsRemoveAll("my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); errorCause(err) != errFileNameTooLong { t.Fatal(err) } } diff --git a/cmd/fs-v1-metadata.go b/cmd/fs-v1-metadata.go index ae0b3532a..f467991db 100644 --- a/cmd/fs-v1-metadata.go +++ b/cmd/fs-v1-metadata.go @@ -125,18 +125,18 @@ func (m *fsMetaV1) AddObjectPart(partNumber int, partName string, partETag strin sort.Sort(byObjectPartNumber(m.Parts)) } -func (m *fsMetaV1) WriteTo(writer io.Writer) (n int64, err error) { +func (m *fsMetaV1) WriteTo(lk *lock.LockedFile) (n int64, err error) { var metadataBytes []byte metadataBytes, err = json.Marshal(m) if err != nil { return 0, traceError(err) } - if err = writer.(*lock.LockedFile).Truncate(0); err != nil { + if err = lk.Truncate(0); err != nil { return 0, traceError(err) } - if _, err = writer.Write(metadataBytes); err != nil { + if _, err = lk.Write(metadataBytes); err != nil { return 0, traceError(err) } @@ -144,9 +144,14 @@ func (m *fsMetaV1) WriteTo(writer io.Writer) (n int64, err error) { return int64(len(metadataBytes)), nil } -func (m *fsMetaV1) ReadFrom(reader io.Reader) (n int64, err error) { +func (m *fsMetaV1) ReadFrom(lk *lock.LockedFile) (n int64, err error) { var metadataBytes []byte - metadataBytes, err = ioutil.ReadAll(reader) + fi, err := lk.Stat() + if err != nil { + return 0, traceError(err) + } + + metadataBytes, err = ioutil.ReadAll(io.NewSectionReader(lk, 0, fi.Size())) if err != nil { return 0, traceError(err) } diff --git a/cmd/fs-v1-metadata_test.go b/cmd/fs-v1-metadata_test.go index b1163d62f..c31008949 100644 --- a/cmd/fs-v1-metadata_test.go +++ b/cmd/fs-v1-metadata_test.go @@ -18,7 +18,6 @@ package cmd import ( "bytes" - "io" "os" "path/filepath" "testing" @@ -69,10 +68,9 @@ func TestReadFSMetadata(t *testing.T) { } defer rlk.Close() - sectionReader := io.NewSectionReader(rlk, 0, rlk.Size()) // Regular fs metadata reading, no errors expected fsMeta := fsMetaV1{} - if _, err = fsMeta.ReadFrom(sectionReader); err != nil { + if _, err = fsMeta.ReadFrom(rlk.LockedFile); err != nil { t.Fatal("Unexpected error ", err) } @@ -84,7 +82,7 @@ func TestReadFSMetadata(t *testing.T) { file.Write([]byte{'a'}) file.Close() fsMeta = fsMetaV1{} - if _, err := fsMeta.ReadFrom(sectionReader); err == nil { + if _, err := fsMeta.ReadFrom(rlk.LockedFile); err == nil { t.Fatal("Should fail", err) } } @@ -119,10 +117,9 @@ func TestWriteFSMetadata(t *testing.T) { } defer rlk.Close() - sectionReader := io.NewSectionReader(rlk, 0, rlk.Size()) // FS metadata reading, no errors expected (healthy disk) fsMeta := fsMetaV1{} - _, err = fsMeta.ReadFrom(sectionReader) + _, err = fsMeta.ReadFrom(rlk.LockedFile) if err != nil { t.Fatal("Unexpected error ", err) } diff --git a/cmd/fs-v1-multipart-common.go b/cmd/fs-v1-multipart-common.go deleted file mode 100644 index 940b0645e..000000000 --- a/cmd/fs-v1-multipart-common.go +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2016, 2017 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cmd - -import ( - "fmt" - "io" - "runtime" - "time" - - pathutil "path" - - "github.com/minio/minio/pkg/lock" -) - -// Returns if the prefix is a multipart upload. -func (fs fsObjects) isMultipartUpload(bucket, prefix string) bool { - uploadsIDPath := pathJoin(fs.fsPath, bucket, prefix, uploadsJSONFile) - _, err := fsStatFile(uploadsIDPath) - if err != nil { - if err == errFileNotFound { - return false - } - errorIf(err, "Unable to access uploads.json "+uploadsIDPath) - return false - } - return true -} - -// Delete uploads.json file wrapper handling a tricky case on windows. -func (fs fsObjects) deleteUploadsJSON(bucket, object, uploadID string) error { - timeID := fmt.Sprintf("%X", time.Now().UTC().UnixNano()) - tmpPath := pathJoin(fs.fsPath, minioMetaTmpBucket, fs.fsUUID, uploadID+"+"+timeID) - - multipartBucketPath := pathJoin(fs.fsPath, minioMetaMultipartBucket) - uploadPath := pathJoin(multipartBucketPath, bucket, object) - uploadsMetaPath := pathJoin(uploadPath, uploadsJSONFile) - - // Special case for windows please read through. - if runtime.GOOS == globalWindowsOSName { - // Ordinarily windows does not permit deletion or renaming of files still - // in use, but if all open handles to that file were opened with FILE_SHARE_DELETE - // then it can permit renames and deletions of open files. - // - // There are however some gotchas with this, and it is worth listing them here. - // Firstly, Windows never allows you to really delete an open file, rather it is - // flagged as delete pending and its entry in its directory remains visible - // (though no new file handles may be opened to it) and when the very last - // open handle to the file in the system is closed, only then is it truly - // deleted. Well, actually only sort of truly deleted, because Windows only - // appears to remove the file entry from the directory, but in fact that - // entry is merely hidden and actually still exists and attempting to create - // a file with the same name will return an access denied error. How long it - // silently exists for depends on a range of factors, but put it this way: - // if your code loops creating and deleting the same file name as you might - // when operating a lock file, you're going to see lots of random spurious - // access denied errors and truly dismal lock file performance compared to POSIX. - // - // We work-around these un-POSIX file semantics by taking a dual step to - // deleting files. Firstly, it renames the file to tmp location into multipartTmpBucket - // We always open files with FILE_SHARE_DELETE permission enabled, with that - // flag Windows permits renaming and deletion, and because the name was changed - // to a very random name somewhere not in its origin directory before deletion, - // you don't see those unexpected random errors when creating files with the - // same name as a recently deleted file as you do anywhere else on Windows. - // Because the file is probably not in its original containing directory any more, - // deletions of that directory will not fail with “directory not empty” as they - // otherwise normally would either. - fsRenameFile(uploadsMetaPath, tmpPath) - - // Proceed to deleting the directory. - if err := fsDeleteFile(multipartBucketPath, uploadPath); err != nil { - return err - } - - // Finally delete the renamed file. - return fsDeleteFile(pathutil.Dir(tmpPath), tmpPath) - } - return fsDeleteFile(multipartBucketPath, uploadsMetaPath) -} - -// Removes the uploadID, called either by CompleteMultipart of AbortMultipart. If the resuling uploads -// slice is empty then we remove/purge the file. -func (fs fsObjects) removeUploadID(bucket, object, uploadID string, rwlk *lock.LockedFile) error { - uploadIDs := uploadsV1{} - _, err := uploadIDs.ReadFrom(io.NewSectionReader(rwlk, 0, rwlk.Size())) - if err != nil { - return err - } - - // Removes upload id from the uploads list. - uploadIDs.RemoveUploadID(uploadID) - - // Check this is the last entry. - if uploadIDs.IsEmpty() { - // No more uploads left, so we delete `uploads.json` file. - return fs.deleteUploadsJSON(bucket, object, uploadID) - } // else not empty - - // Write update `uploads.json`. - _, err = uploadIDs.WriteTo(rwlk) - return err -} - -// Adds a new uploadID if no previous `uploads.json` is -// found we initialize a new one. -func (fs fsObjects) addUploadID(bucket, object, uploadID string, initiated time.Time, rwlk *lock.LockedFile) error { - uploadIDs := uploadsV1{} - - _, err := uploadIDs.ReadFrom(io.NewSectionReader(rwlk, 0, rwlk.Size())) - // For all unexpected errors, we return. - if err != nil && errorCause(err) != io.EOF { - return err - } - - // If we couldn't read anything, we assume a default - // (empty) upload info. - if errorCause(err) == io.EOF { - uploadIDs = newUploadsV1("fs") - } - - // Adds new upload id to the list. - uploadIDs.AddUploadID(uploadID, initiated) - - // Write update `uploads.json`. - _, err = uploadIDs.WriteTo(rwlk) - return err -} diff --git a/cmd/fs-v1-multipart-common_test.go b/cmd/fs-v1-multipart-common_test.go deleted file mode 100644 index 026799580..000000000 --- a/cmd/fs-v1-multipart-common_test.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cmd - -import ( - "path/filepath" - "testing" -) - -// TestFSWriteUploadJSON - tests for writeUploadJSON for FS -func TestFSWriteUploadJSON(t *testing.T) { - // Prepare for tests - disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix()) - defer removeAll(disk) - - obj := initFSObjects(disk, t) - - bucketName := "bucket" - objectName := "object" - - obj.MakeBucket(bucketName) - _, err := obj.NewMultipartUpload(bucketName, objectName, nil) - if err != nil { - t.Fatal("Unexpected err: ", err) - } - - // newMultipartUpload will fail. - removeAll(disk) // Remove disk. - _, err = obj.NewMultipartUpload(bucketName, objectName, nil) - if err != nil { - if _, ok := errorCause(err).(BucketNotFound); !ok { - t.Fatal("Unexpected err: ", err) - } - } -} diff --git a/cmd/fs-v1-multipart.go b/cmd/fs-v1-multipart.go index a1079f795..4ae57635c 100644 --- a/cmd/fs-v1-multipart.go +++ b/cmd/fs-v1-multipart.go @@ -24,12 +24,128 @@ import ( "io" "os" pathutil "path" + "runtime" "strings" "time" + "github.com/minio/minio/pkg/lock" "github.com/minio/sha256-simd" ) +// Returns if the prefix is a multipart upload. +func (fs fsObjects) isMultipartUpload(bucket, prefix string) bool { + uploadsIDPath := pathJoin(fs.fsPath, bucket, prefix, uploadsJSONFile) + _, err := fsStatFile(uploadsIDPath) + if err != nil { + if err == errFileNotFound { + return false + } + errorIf(err, "Unable to access uploads.json "+uploadsIDPath) + return false + } + return true +} + +// Delete uploads.json file wrapper handling a tricky case on windows. +func (fs fsObjects) deleteUploadsJSON(bucket, object, uploadID string) error { + timeID := fmt.Sprintf("%X", time.Now().UTC().UnixNano()) + tmpPath := pathJoin(fs.fsPath, minioMetaTmpBucket, fs.fsUUID, uploadID+"+"+timeID) + + multipartBucketPath := pathJoin(fs.fsPath, minioMetaMultipartBucket) + uploadPath := pathJoin(multipartBucketPath, bucket, object) + uploadsMetaPath := pathJoin(uploadPath, uploadsJSONFile) + + // Special case for windows please read through. + if runtime.GOOS == globalWindowsOSName { + // Ordinarily windows does not permit deletion or renaming of files still + // in use, but if all open handles to that file were opened with FILE_SHARE_DELETE + // then it can permit renames and deletions of open files. + // + // There are however some gotchas with this, and it is worth listing them here. + // Firstly, Windows never allows you to really delete an open file, rather it is + // flagged as delete pending and its entry in its directory remains visible + // (though no new file handles may be opened to it) and when the very last + // open handle to the file in the system is closed, only then is it truly + // deleted. Well, actually only sort of truly deleted, because Windows only + // appears to remove the file entry from the directory, but in fact that + // entry is merely hidden and actually still exists and attempting to create + // a file with the same name will return an access denied error. How long it + // silently exists for depends on a range of factors, but put it this way: + // if your code loops creating and deleting the same file name as you might + // when operating a lock file, you're going to see lots of random spurious + // access denied errors and truly dismal lock file performance compared to POSIX. + // + // We work-around these un-POSIX file semantics by taking a dual step to + // deleting files. Firstly, it renames the file to tmp location into multipartTmpBucket + // We always open files with FILE_SHARE_DELETE permission enabled, with that + // flag Windows permits renaming and deletion, and because the name was changed + // to a very random name somewhere not in its origin directory before deletion, + // you don't see those unexpected random errors when creating files with the + // same name as a recently deleted file as you do anywhere else on Windows. + // Because the file is probably not in its original containing directory any more, + // deletions of that directory will not fail with "directory not empty" as they + // otherwise normally would either. + fsRenameFile(uploadsMetaPath, tmpPath) + + // Proceed to deleting the directory. + if err := fsDeleteFile(multipartBucketPath, uploadPath); err != nil { + return err + } + + // Finally delete the renamed file. + return fsDeleteFile(pathutil.Dir(tmpPath), tmpPath) + } + return fsDeleteFile(multipartBucketPath, uploadsMetaPath) +} + +// Removes the uploadID, called either by CompleteMultipart of AbortMultipart. If the resuling uploads +// slice is empty then we remove/purge the file. +func (fs fsObjects) removeUploadID(bucket, object, uploadID string, rwlk *lock.LockedFile) error { + uploadIDs := uploadsV1{} + _, err := uploadIDs.ReadFrom(rwlk) + if err != nil { + return err + } + + // Removes upload id from the uploads list. + uploadIDs.RemoveUploadID(uploadID) + + // Check this is the last entry. + if uploadIDs.IsEmpty() { + // No more uploads left, so we delete `uploads.json` file. + return fs.deleteUploadsJSON(bucket, object, uploadID) + } // else not empty + + // Write update `uploads.json`. + _, err = uploadIDs.WriteTo(rwlk) + return err +} + +// Adds a new uploadID if no previous `uploads.json` is +// found we initialize a new one. +func (fs fsObjects) addUploadID(bucket, object, uploadID string, initiated time.Time, rwlk *lock.LockedFile) error { + uploadIDs := uploadsV1{} + + _, err := uploadIDs.ReadFrom(rwlk) + // For all unexpected errors, we return. + if err != nil && errorCause(err) != io.EOF { + return err + } + + // If we couldn't read anything, we assume a default + // (empty) upload info. + if errorCause(err) == io.EOF { + uploadIDs = newUploadsV1("fs") + } + + // Adds new upload id to the list. + uploadIDs.AddUploadID(uploadID, initiated) + + // Write update `uploads.json`. + _, err = uploadIDs.WriteTo(rwlk) + return err +} + // listMultipartUploadIDs - list all the upload ids from a marker up to 'count'. func (fs fsObjects) listMultipartUploadIDs(bucketName, objectName, uploadIDMarker string, count int) ([]uploadMetadata, bool, error) { var uploads []uploadMetadata @@ -52,7 +168,7 @@ func (fs fsObjects) listMultipartUploadIDs(bucketName, objectName, uploadIDMarke // Read `uploads.json`. uploadIDs := uploadsV1{} - if _, err = uploadIDs.ReadFrom(io.NewSectionReader(rlk, 0, rlk.Size())); err != nil { + if _, err = uploadIDs.ReadFrom(rlk.LockedFile); err != nil { return nil, false, err } @@ -335,17 +451,49 @@ func partToAppend(fsMeta fsMetaV1, fsAppendMeta fsMetaV1) (part objectPartInfo, return fsMeta.Parts[nextPartIndex], true } +// CopyObjectPart - similar to PutObjectPart but reads data from an existing +// object. Internally incoming data is written to '.minio.sys/tmp' location +// and safely renamed to '.minio.sys/multipart' for reach parts. +func (fs fsObjects) CopyObjectPart(srcBucket, srcObject, dstBucket, dstObject, uploadID string, partID int, startOffset int64, length int64) (PartInfo, error) { + if err := checkNewMultipartArgs(srcBucket, srcObject, fs); err != nil { + return PartInfo{}, err + } + + // Initialize pipe. + pipeReader, pipeWriter := io.Pipe() + + go func() { + startOffset := int64(0) // Read the whole file. + if gerr := fs.GetObject(srcBucket, srcObject, startOffset, length, pipeWriter); gerr != nil { + errorIf(gerr, "Unable to read %s/%s.", srcBucket, srcObject) + pipeWriter.CloseWithError(gerr) + return + } + pipeWriter.Close() // Close writer explicitly signalling we wrote all data. + }() + + partInfo, err := fs.PutObjectPart(dstBucket, dstObject, uploadID, partID, length, pipeReader, "", "") + if err != nil { + return PartInfo{}, toObjectErr(err, dstBucket, dstObject) + } + + // Explicitly close the reader. + pipeReader.Close() + + return partInfo, nil +} + // PutObjectPart - reads incoming data until EOF for the part file on // an ongoing multipart transaction. Internally incoming data is // written to '.minio.sys/tmp' location and safely renamed to // '.minio.sys/multipart' for reach parts. -func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (string, error) { +func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (PartInfo, error) { if err := checkPutObjectPartArgs(bucket, object, fs); err != nil { - return "", err + return PartInfo{}, err } if _, err := fs.statBucketDir(bucket); err != nil { - return "", toObjectErr(err, bucket) + return PartInfo{}, toObjectErr(err, bucket) } // Hold the lock so that two parallel complete-multipart-uploads @@ -358,9 +506,9 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s uploadsPath := pathJoin(fs.fsPath, minioMetaMultipartBucket, bucket, object, uploadsJSONFile) if _, err := fs.rwPool.Open(uploadsPath); err != nil { if err == errFileNotFound || err == errFileAccessDenied { - return "", traceError(InvalidUploadID{UploadID: uploadID}) + return PartInfo{}, traceError(InvalidUploadID{UploadID: uploadID}) } - return "", toObjectErr(traceError(err), bucket, object) + return PartInfo{}, toObjectErr(traceError(err), bucket, object) } defer fs.rwPool.Close(uploadsPath) @@ -371,16 +519,16 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s rwlk, err := fs.rwPool.Write(fsMetaPath) if err != nil { if err == errFileNotFound || err == errFileAccessDenied { - return "", traceError(InvalidUploadID{UploadID: uploadID}) + return PartInfo{}, traceError(InvalidUploadID{UploadID: uploadID}) } - return "", toObjectErr(traceError(err), bucket, object) + return PartInfo{}, toObjectErr(traceError(err), bucket, object) } defer rwlk.Close() fsMeta := fsMetaV1{} - _, err = fsMeta.ReadFrom(io.NewSectionReader(rwlk, 0, rwlk.Size())) + _, err = fsMeta.ReadFrom(rwlk) if err != nil { - return "", toObjectErr(err, minioMetaMultipartBucket, fsMetaPath) + return PartInfo{}, toObjectErr(err, minioMetaMultipartBucket, fsMetaPath) } partSuffix := fmt.Sprintf("object%d", partID) @@ -418,14 +566,14 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s bytesWritten, cErr := fsCreateFile(fsPartPath, teeReader, buf, size) if cErr != nil { fsRemoveFile(fsPartPath) - return "", toObjectErr(cErr, minioMetaTmpBucket, tmpPartPath) + return PartInfo{}, toObjectErr(cErr, minioMetaTmpBucket, tmpPartPath) } // Should return IncompleteBody{} error when reader has fewer // bytes than specified in request header. if bytesWritten < size { fsRemoveFile(fsPartPath) - return "", traceError(IncompleteBody{}) + return PartInfo{}, traceError(IncompleteBody{}) } // Delete temporary part in case of failure. If @@ -436,14 +584,14 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s newMD5Hex := hex.EncodeToString(md5Writer.Sum(nil)) if md5Hex != "" { if newMD5Hex != md5Hex { - return "", traceError(BadDigest{md5Hex, newMD5Hex}) + return PartInfo{}, traceError(BadDigest{md5Hex, newMD5Hex}) } } if sha256sum != "" { newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) if newSHA256sum != sha256sum { - return "", traceError(SHA256Mismatch{}) + return PartInfo{}, traceError(SHA256Mismatch{}) } } @@ -456,14 +604,20 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s fsNSPartPath := pathJoin(fs.fsPath, minioMetaMultipartBucket, partPath) if err = fsRenameFile(fsPartPath, fsNSPartPath); err != nil { partLock.Unlock() - return "", toObjectErr(err, minioMetaMultipartBucket, partPath) + return PartInfo{}, toObjectErr(err, minioMetaMultipartBucket, partPath) } // Save the object part info in `fs.json`. fsMeta.AddObjectPart(partID, partSuffix, newMD5Hex, size) if _, err = fsMeta.WriteTo(rwlk); err != nil { partLock.Unlock() - return "", toObjectErr(err, minioMetaMultipartBucket, uploadIDPath) + return PartInfo{}, toObjectErr(err, minioMetaMultipartBucket, uploadIDPath) + } + + partNamePath := pathJoin(fs.fsPath, minioMetaMultipartBucket, uploadIDPath, partSuffix) + fi, err := fsStatFile(partNamePath) + if err != nil { + return PartInfo{}, toObjectErr(err, minioMetaMultipartBucket, partSuffix) } // Append the part in background. @@ -477,7 +631,12 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s partLock.Unlock() }() - return newMD5Hex, nil + return PartInfo{ + PartNumber: partID, + LastModified: fi.ModTime(), + ETag: newMD5Hex, + Size: fi.Size(), + }, nil } // listObjectParts - wrapper scanning through @@ -499,7 +658,7 @@ func (fs fsObjects) listObjectParts(bucket, object, uploadID string, partNumberM defer fs.rwPool.Close(fsMetaPath) fsMeta := fsMetaV1{} - _, err = fsMeta.ReadFrom((io.NewSectionReader(metaFile, 0, metaFile.Size()))) + _, err = fsMeta.ReadFrom(metaFile.LockedFile) if err != nil { return ListPartsInfo{}, toObjectErr(err, minioMetaBucket, fsMetaPath) } @@ -517,9 +676,9 @@ func (fs fsObjects) listObjectParts(bucket, object, uploadID string, partNumberM partNamePath := pathJoin(fs.fsPath, minioMetaMultipartBucket, uploadIDPath, part.Name) fi, err = fsStatFile(partNamePath) if err != nil { - return ListPartsInfo{}, toObjectErr(traceError(err), minioMetaMultipartBucket, partNamePath) + return ListPartsInfo{}, toObjectErr(err, minioMetaMultipartBucket, partNamePath) } - result.Parts = append(result.Parts, partInfo{ + result.Parts = append(result.Parts, PartInfo{ PartNumber: part.Number, ETag: part.ETag, LastModified: fi.ModTime(), @@ -630,7 +789,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload fsMeta := fsMetaV1{} // Read saved fs metadata for ongoing multipart. - _, err = fsMeta.ReadFrom(io.NewSectionReader(rlk, 0, rlk.Size())) + _, err = fsMeta.ReadFrom(rlk.LockedFile) if err != nil { fs.rwPool.Close(fsMetaPathMultipart) return ObjectInfo{}, toObjectErr(err, minioMetaMultipartBucket, fsMetaPathMultipart) @@ -767,7 +926,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload multipartObjectDir := pathJoin(fs.fsPath, minioMetaMultipartBucket, bucket, object) multipartUploadIDDir := pathJoin(multipartObjectDir, uploadID) if err = fsRemoveUploadIDPath(multipartObjectDir, multipartUploadIDDir); err != nil { - return ObjectInfo{}, toObjectErr(traceError(err), bucket, object) + return ObjectInfo{}, toObjectErr(err, bucket, object) } // Remove entry from `uploads.json`. @@ -777,7 +936,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload fi, err := fsStatFile(fsNSObjPath) if err != nil { - return ObjectInfo{}, toObjectErr(traceError(err), bucket, object) + return ObjectInfo{}, toObjectErr(err, bucket, object) } // Return object info. @@ -845,7 +1004,7 @@ func (fs fsObjects) AbortMultipartUpload(bucket, object, uploadID string) error multipartObjectDir := pathJoin(fs.fsPath, minioMetaMultipartBucket, bucket, object) multipartUploadIDDir := pathJoin(multipartObjectDir, uploadID) if err = fsRemoveUploadIDPath(multipartObjectDir, multipartUploadIDDir); err != nil { - return toObjectErr(traceError(err), bucket, object) + return toObjectErr(err, bucket, object) } // Remove entry from `uploads.json`. diff --git a/cmd/fs-v1-multipart_test.go b/cmd/fs-v1-multipart_test.go index ee6126fed..75ef537a5 100644 --- a/cmd/fs-v1-multipart_test.go +++ b/cmd/fs-v1-multipart_test.go @@ -22,6 +22,33 @@ import ( "testing" ) +// TestFSWriteUploadJSON - tests for writeUploadJSON for FS +func TestFSWriteUploadJSON(t *testing.T) { + // Prepare for tests + disk := filepath.Join(globalTestTmpDir, "minio-"+nextSuffix()) + defer removeAll(disk) + + obj := initFSObjects(disk, t) + + bucketName := "bucket" + objectName := "object" + + obj.MakeBucket(bucketName) + _, err := obj.NewMultipartUpload(bucketName, objectName, nil) + if err != nil { + t.Fatal("Unexpected err: ", err) + } + + // newMultipartUpload will fail. + removeAll(disk) // Remove disk. + _, err = obj.NewMultipartUpload(bucketName, objectName, nil) + if err != nil { + if _, ok := errorCause(err).(BucketNotFound); !ok { + t.Fatal("Unexpected err: ", err) + } + } +} + // TestNewMultipartUploadFaultyDisk - test NewMultipartUpload with faulty disks func TestNewMultipartUploadFaultyDisk(t *testing.T) { // Prepare for tests diff --git a/cmd/fs-v1.go b/cmd/fs-v1.go index 6db9c5635..16f3263a3 100644 --- a/cmd/fs-v1.go +++ b/cmd/fs-v1.go @@ -245,7 +245,7 @@ func (fs fsObjects) statBucketDir(bucket string) (os.FileInfo, error) { } st, err := fsStatDir(bucketDir) if err != nil { - return nil, traceError(err) + return nil, err } return st, nil } @@ -259,7 +259,7 @@ func (fs fsObjects) MakeBucket(bucket string) error { } if err = fsMkdir(bucketDir); err != nil { - return toObjectErr(traceError(err), bucket) + return toObjectErr(err, bucket) } return nil @@ -283,7 +283,7 @@ func (fs fsObjects) GetBucketInfo(bucket string) (BucketInfo, error) { // ListBuckets - list all s3 compatible buckets (directories) at fsPath. func (fs fsObjects) ListBuckets() ([]BucketInfo, error) { if err := checkPathLength(fs.fsPath); err != nil { - return nil, err + return nil, traceError(err) } var bucketInfos []BucketInfo entries, err := readDir(preparePath(fs.fsPath)) @@ -301,9 +301,9 @@ func (fs fsObjects) ListBuckets() ([]BucketInfo, error) { fi, err = fsStatDir(pathJoin(fs.fsPath, entry)) if err != nil { // If the directory does not exist, skip the entry. - if err == errVolumeNotFound { + if errorCause(err) == errVolumeNotFound { continue - } else if err == errVolumeAccessDenied { + } else if errorCause(err) == errVolumeAccessDenied { // Skip the entry if its a file. continue } @@ -376,7 +376,7 @@ func (fs fsObjects) CopyObject(srcBucket, srcObject, dstBucket, dstObject string // Stat the file to get file size. fi, err := fsStatFile(pathJoin(fs.fsPath, srcBucket, srcObject)) if err != nil { - return ObjectInfo{}, toObjectErr(traceError(err), srcBucket, srcObject) + return ObjectInfo{}, toObjectErr(err, srcBucket, srcObject) } // Check if this request is only metadata update. @@ -386,7 +386,7 @@ func (fs fsObjects) CopyObject(srcBucket, srcObject, dstBucket, dstObject string var wlk *lock.LockedFile wlk, err = fs.rwPool.Write(fsMetaPath) if err != nil { - return ObjectInfo{}, toObjectErr(err, srcBucket, srcObject) + return ObjectInfo{}, toObjectErr(traceError(err), srcBucket, srcObject) } // This close will allow for locks to be synchronized on `fs.json`. defer wlk.Close() @@ -467,7 +467,7 @@ func (fs fsObjects) GetObject(bucket, object string, offset int64, length int64, fsObjPath := pathJoin(fs.fsPath, bucket, object) reader, size, err := fsOpenFile(fsObjPath, offset) if err != nil { - return toObjectErr(traceError(err), bucket, object) + return toObjectErr(err, bucket, object) } defer reader.Close() @@ -505,8 +505,13 @@ func (fs fsObjects) getObjectInfo(bucket, object string) (ObjectInfo, error) { if err == nil { // Read from fs metadata only if it exists. defer fs.rwPool.Close(fsMetaPath) - if _, rerr := fsMeta.ReadFrom(io.NewSectionReader(rlk, 0, rlk.Size())); rerr != nil { - return ObjectInfo{}, toObjectErr(rerr, bucket, object) + if _, rerr := fsMeta.ReadFrom(rlk.LockedFile); rerr != nil { + // `fs.json` can be empty due to previously failed + // PutObject() transaction, if we arrive at such + // a situation we just ignore and continue. + if errorCause(rerr) != io.EOF { + return ObjectInfo{}, toObjectErr(rerr, bucket, object) + } } } @@ -518,7 +523,7 @@ func (fs fsObjects) getObjectInfo(bucket, object string) (ObjectInfo, error) { // Stat the file to get file size. fi, err := fsStatFile(pathJoin(fs.fsPath, bucket, object)) if err != nil { - return ObjectInfo{}, toObjectErr(traceError(err), bucket, object) + return ObjectInfo{}, toObjectErr(err, bucket, object) } return fsMeta.ToObjectInfo(bucket, object, fi), nil @@ -569,7 +574,7 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fsMetaJSONFile) wlk, err = fs.rwPool.Create(fsMetaPath) if err != nil { - return ObjectInfo{}, toObjectErr(err, bucket, object) + return ObjectInfo{}, toObjectErr(traceError(err), bucket, object) } // This close will allow for locks to be synchronized on `fs.json`. defer wlk.Close() @@ -667,7 +672,7 @@ func (fs fsObjects) PutObject(bucket string, object string, size int64, data io. // Stat the file to fetch timestamp, size. fi, err := fsStatFile(pathJoin(fs.fsPath, bucket, object)) if err != nil { - return ObjectInfo{}, toObjectErr(traceError(err), bucket, object) + return ObjectInfo{}, toObjectErr(err, bucket, object) } // Success. @@ -694,20 +699,20 @@ func (fs fsObjects) DeleteObject(bucket, object string) error { defer rwlk.Close() } if lerr != nil && lerr != errFileNotFound { - return toObjectErr(lerr, bucket, object) + return toObjectErr(traceError(lerr), bucket, object) } } // Delete the object. if err := fsDeleteFile(pathJoin(fs.fsPath, bucket), pathJoin(fs.fsPath, bucket, object)); err != nil { - return toObjectErr(traceError(err), bucket, object) + return toObjectErr(err, bucket, object) } if bucket != minioMetaBucket { // Delete the metadata object. err := fsDeleteFile(minioMetaBucketDir, fsMetaPath) - if err != nil && err != errFileNotFound { - return toObjectErr(traceError(err), bucket, object) + if err != nil && errorCause(err) != errFileNotFound { + return toObjectErr(err, bucket, object) } } return nil @@ -726,37 +731,11 @@ func (fs fsObjects) listDirFactory(isLeaf isLeafFunc) listDirFunc { // listDir - lists all the entries at a given prefix and given entry in the prefix. listDir := func(bucket, prefixDir, prefixEntry string) (entries []string, delayIsLeaf bool, err error) { entries, err = readDir(pathJoin(fs.fsPath, bucket, prefixDir)) - if err == nil { - // Listing needs to be sorted. - sort.Strings(entries) - - // Filter entries that have the prefix prefixEntry. - entries = filterMatchingPrefix(entries, prefixEntry) - - // Can isLeaf() check be delayed till when it has to be sent down the - // treeWalkResult channel? - delayIsLeaf = delayIsLeafCheck(entries) - if delayIsLeaf { - return entries, delayIsLeaf, nil - } - - // isLeaf() check has to happen here so that trailing "/" for objects can be removed. - for i, entry := range entries { - if isLeaf(bucket, pathJoin(prefixDir, entry)) { - entries[i] = strings.TrimSuffix(entry, slashSeparator) - } - } - - // Sort again after removing trailing "/" for objects as the previous sort - // does not hold good anymore. - sort.Strings(entries) - - // Succes. - return entries, delayIsLeaf, nil - } // Return error at the end. - - // Error. - return nil, false, err + if err != nil { + return nil, false, err + } + entries, delayIsLeaf = filterListEntries(bucket, prefixDir, entries, prefixEntry, isLeaf) + return entries, delayIsLeaf, nil } // Return list factory instance. @@ -811,7 +790,7 @@ func (fs fsObjects) ListObjects(bucket, prefix, marker, delimiter string, maxKey var fi os.FileInfo fi, err = fsStatFile(pathJoin(fs.fsPath, bucket, entry)) if err != nil { - return ObjectInfo{}, toObjectErr(traceError(err), bucket, entry) + return ObjectInfo{}, toObjectErr(err, bucket, entry) } fsMeta := fsMetaV1{} return fsMeta.ToObjectInfo(bucket, entry, fi), nil diff --git a/cmd/fs-v1_test.go b/cmd/fs-v1_test.go index 97d2d36c4..678b81b93 100644 --- a/cmd/fs-v1_test.go +++ b/cmd/fs-v1_test.go @@ -77,13 +77,11 @@ func TestFSShutdown(t *testing.T) { removeAll(disk) // Test Shutdown with faulty disk - for i := 1; i <= 5; i++ { - fs, disk := prepareTest() - fs.DeleteObject(bucketName, objectName) - removeAll(disk) - if err := fs.Shutdown(); err != nil { - t.Fatal(i, ", Got unexpected fs shutdown error: ", err) - } + fs, disk = prepareTest() + fs.DeleteObject(bucketName, objectName) + removeAll(disk) + if err := fs.Shutdown(); err != nil { + t.Fatal("Got unexpected fs shutdown error: ", err) } } diff --git a/cmd/generic-handlers.go b/cmd/generic-handlers.go index 974045687..0bf9fd9da 100644 --- a/cmd/generic-handlers.go +++ b/cmd/generic-handlers.go @@ -17,6 +17,8 @@ package cmd import ( + "bufio" + "net" "net/http" "path" "strings" @@ -141,8 +143,8 @@ func setBrowserCacheControlHandler(h http.Handler) http.Handler { func (h cacheControlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method == httpGET && guessIsBrowserReq(r) && globalIsBrowserEnabled { // For all browser requests set appropriate Cache-Control policies - if strings.HasPrefix(r.URL.Path, reservedBucket+"/") { - if strings.HasSuffix(r.URL.Path, ".js") || r.URL.Path == reservedBucket+"/favicon.ico" { + if hasPrefix(r.URL.Path, reservedBucket+"/") { + if hasSuffix(r.URL.Path, ".js") || r.URL.Path == reservedBucket+"/favicon.ico" { // For assets set cache expiry of one year. For each release, the name // of the asset name will change and hence it can not be served from cache. w.Header().Set("Cache-Control", "max-age=31536000") @@ -356,3 +358,52 @@ func (h resourceHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Serve HTTP. h.handler.ServeHTTP(w, r) } + +// httpResponseRecorder wraps http.ResponseWriter +// to record some useful http response data. +type httpResponseRecorder struct { + http.ResponseWriter + respStatusCode int +} + +// Wraps ResponseWriter's Write() +func (rww *httpResponseRecorder) Write(b []byte) (int, error) { + return rww.ResponseWriter.Write(b) +} + +// Wraps ResponseWriter's Flush() +func (rww *httpResponseRecorder) Flush() { + rww.ResponseWriter.(http.Flusher).Flush() +} + +// Wraps ResponseWriter's WriteHeader() and record +// the response status code +func (rww *httpResponseRecorder) WriteHeader(httpCode int) { + rww.respStatusCode = httpCode + rww.ResponseWriter.WriteHeader(httpCode) +} + +func (rww *httpResponseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return rww.ResponseWriter.(http.Hijacker).Hijack() +} + +// httpStatsHandler definition: gather HTTP statistics +type httpStatsHandler struct { + handler http.Handler +} + +// setHttpStatsHandler sets a http Stats Handler +func setHTTPStatsHandler(h http.Handler) http.Handler { + return httpStatsHandler{handler: h} +} + +func (h httpStatsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Wraps w to record http response information + ww := &httpResponseRecorder{ResponseWriter: w} + + // Execute the request + h.handler.ServeHTTP(ww, r) + + // Update http statistics + globalHTTPStats.updateStats(r, ww) +} diff --git a/cmd/globals.go b/cmd/globals.go index e1b943b27..56439f635 100644 --- a/cmd/globals.go +++ b/cmd/globals.go @@ -31,11 +31,6 @@ import ( "github.com/minio/minio/pkg/objcache" ) -// Global constants for Minio. -const ( - minGoVersion = ">= 1.7" // Minio requires at least Go v1.7 -) - // minio configuration related constants. const ( globalMinioConfigVersion = "13" @@ -51,6 +46,8 @@ const ( globalMinioDefaultOwnerID = "minio" globalMinioDefaultStorageClass = "STANDARD" globalWindowsOSName = "windows" + globalNetBSDOSName = "netbsd" + globalSolarisOSName = "solaris" // Add new global values here. ) @@ -59,6 +56,9 @@ const ( // can reach that size according to https://aws.amazon.com/articles/1434 maxFormFieldSize = int64(1 * humanize.MiByte) + // Limit memory allocation to store multipart data + maxFormMemory = int64(5 * humanize.MiByte) + // The maximum allowed difference between the request generation time and the server processing time globalMaxSkewTime = 15 * time.Minute ) @@ -82,6 +82,9 @@ var ( // Caching is enabled only for RAM size > 8GiB. globalMaxCacheSize = uint64(0) + // Maximum size of internal objects parts + globalPutPartSize = int64(64 * 1024 * 1024) + // Cache expiry. globalCacheExpiry = objcache.DefaultExpiry @@ -110,15 +113,21 @@ var ( // Minio server user agent string. globalServerUserAgent = "Minio/" + ReleaseTag + " (" + runtime.GOOS + "; " + runtime.GOARCH + ")" - // Access key passed from the environment - globalEnvAccessKey = os.Getenv("MINIO_ACCESS_KEY") - - // Secret key passed from the environment - globalEnvSecretKey = os.Getenv("MINIO_SECRET_KEY") + // Set to true if credentials were passed from env, default is false. + globalIsEnvCreds = false // url.URL endpoints of disks that belong to the object storage. globalEndpoints = []*url.URL{} + // Global server's network statistics + globalConnStats = newConnStats() + + // Global HTTP request statisitics + globalHTTPStats = newHTTPStats() + + // Time when object layer was initialized on start up. + globalBootTime time.Time + // Add new variable global values here. ) diff --git a/cmd/handler-utils.go b/cmd/handler-utils.go index a97f0f192..3b0e852e1 100644 --- a/cmd/handler-utils.go +++ b/cmd/handler-utils.go @@ -18,7 +18,6 @@ package cmd import ( "io" - "io/ioutil" "mime/multipart" "net/http" "strings" @@ -158,33 +157,52 @@ func extractMetadataFromForm(formValues map[string]string) map[string]string { } // Extract form fields and file data from a HTTP POST Policy -func extractPostPolicyFormValues(reader *multipart.Reader) (filePart io.Reader, fileName string, formValues map[string]string, err error) { +func extractPostPolicyFormValues(form *multipart.Form) (filePart io.ReadCloser, fileName string, fileSize int64, formValues map[string]string, err error) { /// HTML Form values formValues = make(map[string]string) fileName = "" - for err == nil { - var part *multipart.Part - part, err = reader.NextPart() - if part != nil { - canonicalFormName := http.CanonicalHeaderKey(part.FormName()) - if canonicalFormName != "File" { - var buffer []byte - limitReader := io.LimitReader(part, maxFormFieldSize+1) - buffer, err = ioutil.ReadAll(limitReader) - if err != nil { - return nil, "", nil, err - } - if int64(len(buffer)) > maxFormFieldSize { - return nil, "", nil, errSizeUnexpected - } - formValues[canonicalFormName] = string(buffer) - } else { - filePart = part - fileName = part.FileName() - // As described in S3 spec, we expect file to be the last form field - break + + // Iterate over form values + for k, v := range form.Value { + canonicalFormName := http.CanonicalHeaderKey(k) + // Check if value's field exceeds S3 limit + if int64(len(v[0])) > maxFormFieldSize { + return nil, "", 0, nil, traceError(errSizeUnexpected) + } + // Set the form value + formValues[canonicalFormName] = v[0] + } + + // Iterator until we find a valid File field and break + for k, v := range form.File { + canonicalFormName := http.CanonicalHeaderKey(k) + if canonicalFormName == "File" { + if len(v) == 0 { + return nil, "", 0, nil, traceError(errInvalidArgument) } + // Fetch fileHeader which has the uploaded file information + fileHeader := v[0] + // Set filename + fileName = fileHeader.Filename + // Open the uploaded part + filePart, err = fileHeader.Open() + if err != nil { + return nil, "", 0, nil, traceError(err) + } + // Compute file size + fileSize, err = filePart.(io.Seeker).Seek(0, 2) + if err != nil { + return nil, "", 0, nil, traceError(err) + } + // Reset Seek to the beginning + _, err = filePart.(io.Seeker).Seek(0, 0) + if err != nil { + return nil, "", 0, nil, traceError(err) + } + // File found and ready for reading + break } } - return filePart, fileName, formValues, nil + + return filePart, fileName, fileSize, formValues, nil } diff --git a/cmd/jwt.go b/cmd/jwt.go index 549617cab..54f4668f7 100644 --- a/cmd/jwt.go +++ b/cmd/jwt.go @@ -38,12 +38,15 @@ const ( defaultInterNodeJWTExpiry = 100 * 365 * 24 * time.Hour ) -var errInvalidAccessKeyLength = errors.New("Invalid access key, access key should be 5 to 20 characters in length") -var errInvalidSecretKeyLength = errors.New("Invalid secret key, secret key should be 8 to 40 characters in length") +var ( + errInvalidAccessKeyLength = errors.New("Invalid access key, access key should be 5 to 20 characters in length") + errInvalidSecretKeyLength = errors.New("Invalid secret key, secret key should be 8 to 40 characters in length") -var errInvalidAccessKeyID = errors.New("The access key ID you provided does not exist in our records") -var errAuthentication = errors.New("Authentication failed, check your access credentials") -var errNoAuthToken = errors.New("JWT token missing") + errInvalidAccessKeyID = errors.New("The access key ID you provided does not exist in our records") + errChangeCredNotAllowed = errors.New("Changing access key and secret key not allowed") + errAuthentication = errors.New("Authentication failed, check your access credentials") + errNoAuthToken = errors.New("JWT token missing") +) func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, error) { // Trim spaces. @@ -65,9 +68,15 @@ func authenticateJWT(accessKey, secretKey string, expiry time.Duration) (string, // Validate secret key. // Using bcrypt to avoid timing attacks. - hashedSecretKey, _ := bcrypt.GenerateFromPassword([]byte(serverCred.SecretKey), bcrypt.DefaultCost) - if bcrypt.CompareHashAndPassword(hashedSecretKey, []byte(secretKey)) != nil { - return "", errAuthentication + if serverCred.secretKeyHash != nil { + if bcrypt.CompareHashAndPassword(serverCred.secretKeyHash, []byte(secretKey)) != nil { + return "", errAuthentication + } + } else { + // Secret key hash not set then generate and validate. + if bcrypt.CompareHashAndPassword(mustGetHashedSecretKey(serverCred.SecretKey), []byte(secretKey)) != nil { + return "", errAuthentication + } } utcNow := time.Now().UTC() @@ -107,13 +116,13 @@ func isAuthTokenValid(tokenString string) bool { } func isHTTPRequestValid(req *http.Request) bool { - return webReqestAuthenticate(req) == nil + return webRequestAuthenticate(req) == nil } // Check if the request is authenticated. // Returns nil if the request is authenticated. errNoAuthToken if token missing. // Returns errAuthentication for all other errors. -func webReqestAuthenticate(req *http.Request) error { +func webRequestAuthenticate(req *http.Request) error { jwtToken, err := jwtreq.ParseFromRequest(req, jwtreq.AuthorizationHeaderExtractor, keyFuncCallback) if err != nil { if err == jwtreq.ErrNoTokenInRequest { diff --git a/cmd/jwt_test.go b/cmd/jwt_test.go index 32cdfa8fe..c8b531269 100644 --- a/cmd/jwt_test.go +++ b/cmd/jwt_test.go @@ -75,10 +75,40 @@ func testAuthenticate(authType string, t *testing.T) { } } -func TestNodeAuthenticate(t *testing.T) { +func TestAuthenticateNode(t *testing.T) { testAuthenticate("node", t) } -func TestWebAuthenticate(t *testing.T) { +func TestAuthenticateWeb(t *testing.T) { testAuthenticate("web", t) } + +func BenchmarkAuthenticateNode(b *testing.B) { + testPath, err := newTestConfig(globalMinioDefaultRegion) + if err != nil { + b.Fatalf("unable initialize config file, %s", err) + } + defer removeAll(testPath) + + creds := serverConfig.GetCredential() + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + authenticateNode(creds.AccessKey, creds.SecretKey) + } +} + +func BenchmarkAuthenticateWeb(b *testing.B) { + testPath, err := newTestConfig(globalMinioDefaultRegion) + if err != nil { + b.Fatalf("unable initialize config file, %s", err) + } + defer removeAll(testPath) + + creds := serverConfig.GetCredential() + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + authenticateWeb(creds.AccessKey, creds.SecretKey) + } +} diff --git a/cmd/lockinfo-handlers.go b/cmd/lockinfo-handlers.go index 9fd98a65f..aa3fb234d 100644 --- a/cmd/lockinfo-handlers.go +++ b/cmd/lockinfo-handlers.go @@ -16,10 +16,7 @@ package cmd -import ( - "strings" - "time" -) +import "time" // SystemLockState - Structure to fill the lock state of entire object storage. // That is the total locks held, total calls blocked on locks and state of all the locks for the entire system. @@ -68,8 +65,8 @@ type OpsLockState struct { Duration time.Duration `json:"duration"` // Duration since the lock was held. } -// listLocksInfo - Fetches locks held on bucket, matching prefix older than relTime. -func listLocksInfo(bucket, prefix string, relTime time.Duration) []VolumeLockInfo { +// listLocksInfo - Fetches locks held on bucket, matching prefix held for longer than duration. +func listLocksInfo(bucket, prefix string, duration time.Duration) []VolumeLockInfo { globalNSMutex.lockMapMutex.Lock() defer globalNSMutex.lockMapMutex.Unlock() @@ -82,7 +79,7 @@ func listLocksInfo(bucket, prefix string, relTime time.Duration) []VolumeLockInf continue } // N B empty prefix matches all param.path. - if !strings.HasPrefix(param.path, prefix) { + if !hasPrefix(param.path, prefix) { continue } @@ -95,11 +92,12 @@ func listLocksInfo(bucket, prefix string, relTime time.Duration) []VolumeLockInf } // Filter locks that are held on bucket, prefix. for opsID, lockInfo := range debugLock.lockInfo { + // filter locks that were held for longer than duration. elapsed := timeNow.Sub(lockInfo.since) - if elapsed < relTime { + if elapsed < duration { continue } - // Add locks that are older than relTime. + // Add locks that are held for longer than duration. volLockInfo.LockDetailsOnObject = append(volLockInfo.LockDetailsOnObject, OpsLockState{ OperationID: opsID, diff --git a/cmd/lockinfo-handlers_test.go b/cmd/lockinfo-handlers_test.go index 78c969151..ebb0f23d5 100644 --- a/cmd/lockinfo-handlers_test.go +++ b/cmd/lockinfo-handlers_test.go @@ -45,34 +45,34 @@ func TestListLocksInfo(t *testing.T) { testCases := []struct { bucket string prefix string - relTime time.Duration + duration time.Duration numLocks int }{ // Test 1 - Matches all the locks acquired above. { bucket: "bucket1", prefix: "prefix1", - relTime: time.Duration(0 * time.Second), + duration: time.Duration(0 * time.Second), numLocks: 20, }, // Test 2 - Bucket doesn't match. { bucket: "bucket", prefix: "prefix1", - relTime: time.Duration(0 * time.Second), + duration: time.Duration(0 * time.Second), numLocks: 0, }, // Test 3 - Prefix doesn't match. { bucket: "bucket1", prefix: "prefix11", - relTime: time.Duration(0 * time.Second), + duration: time.Duration(0 * time.Second), numLocks: 0, }, } for i, test := range testCases { - actual := listLocksInfo(test.bucket, test.prefix, test.relTime) + actual := listLocksInfo(test.bucket, test.prefix, test.duration) if len(actual) != test.numLocks { t.Errorf("Test %d - Expected %d locks but observed %d locks", i+1, test.numLocks, len(actual)) diff --git a/cmd/logger-console-hook.go b/cmd/logger-console-hook.go index 653b6ff04..fdc5264e8 100644 --- a/cmd/logger-console-hook.go +++ b/cmd/logger-console-hook.go @@ -26,7 +26,7 @@ type consoleLogger struct { // enable console logger. func enableConsoleLogger() { - clogger := serverConfig.GetConsoleLogger() + clogger := serverConfig.Logger.GetConsole() if !clogger.Enable { return } diff --git a/cmd/logger-file-hook.go b/cmd/logger-file-hook.go index a0aad40a5..c7b5f6652 100644 --- a/cmd/logger-file-hook.go +++ b/cmd/logger-file-hook.go @@ -35,7 +35,7 @@ type localFile struct { } func enableFileLogger() { - flogger := serverConfig.GetFileLogger() + flogger := serverConfig.Logger.GetFile() if !flogger.Enable || flogger.Filename == "" { return } diff --git a/cmd/logger.go b/cmd/logger.go index 733e5606e..4aba14543 100644 --- a/cmd/logger.go +++ b/cmd/logger.go @@ -39,11 +39,41 @@ var log = struct { // - console [default] // - file type logger struct { + sync.RWMutex Console consoleLogger `json:"console"` File fileLogger `json:"file"` // Add new loggers here. } +/// Logger related. + +// SetFile set new file logger. +func (l *logger) SetFile(flogger fileLogger) { + l.Lock() + defer l.Unlock() + l.File = flogger +} + +// GetFileLogger get current file logger. +func (l *logger) GetFile() fileLogger { + l.RLock() + defer l.RUnlock() + return l.File +} + +// SetConsole set new console logger. +func (l *logger) SetConsole(clogger consoleLogger) { + l.Lock() + defer l.Unlock() + l.Console = clogger +} + +func (l *logger) GetConsole() consoleLogger { + l.RLock() + defer l.RUnlock() + return l.Console +} + // Get file, line, function name of the caller. func callerSource() string { pc, file, line, success := runtime.Caller(2) diff --git a/cmd/main.go b/cmd/main.go index db214201e..f490d2582 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -53,24 +53,18 @@ DESCRIPTION: {{.Description}} USAGE: - minio {{if .Flags}}[flags] {{end}}command{{if .Flags}}{{end}} [arguments...] + minio {{if .VisibleFlags}}[flags] {{end}}command{{if .VisibleFlags}}{{end}} [arguments...] COMMANDS: - {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{if .Flags}} + {{range .VisibleCommands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{if .VisibleFlags}} FLAGS: - {{range .Flags}}{{.}} + {{range .VisibleFlags}}{{.}} {{end}}{{end}} VERSION: ` + Version + `{{ "\n"}}` -// init - check the environment before main starts -func init() { - // Check if minio was compiled using a supported version of Golang. - checkGoVersion() -} - func migrate() { // Migrate config file err := migrateConfig() @@ -94,7 +88,7 @@ func findClosestCommands(command string) []string { sort.Strings(closestCommands) // Suggest other close commands - allow missed, wrongly added and // even transposed characters - for _, value := range commandsTree.walk(commandsTree.root) { + for _, value := range commandsTree.Walk(commandsTree.Root()) { if sort.SearchStrings(closestCommands, value.(string)) < len(closestCommands) { continue } @@ -151,18 +145,40 @@ func checkMainSyntax(c *cli.Context) { func checkUpdate() { // Do not print update messages, if quiet flag is set. if !globalQuiet { - updateMsg, _, err := getReleaseUpdate(minioUpdateStableURL, 1*time.Second) + older, downloadURL, err := getUpdateInfo(1 * time.Second) if err != nil { - // Ignore any errors during getReleaseUpdate(), possibly - // because of network errors. + // Its OK to ignore any errors during getUpdateInfo() here. return } - if updateMsg.Update { - console.Println(updateMsg) + if older > time.Duration(0) { + console.Println(colorizeUpdateMessage(downloadURL, older)) } } } +// Initializes a new config if it doesn't exist, else migrates any old config +// to newer config and finally loads the config to memory. +func initConfig() { + envCreds := mustGetCredentialFromEnv() + + // Config file does not exist, we create it fresh and return upon success. + if !isConfigFileExists() { + if err := newConfig(envCreds); err != nil { + console.Fatalf("Unable to initialize minio config for the first time. Err: %s.\n", err) + } + console.Println("Created minio configuration file successfully at " + mustGetConfigPath()) + return + } + + // Migrate any old version of config / state files to newer format. + migrate() + + // Once we have migrated all the old config, now load them. + if err := loadConfig(envCreds); err != nil { + console.Fatalf("Unable to initialize minio config. Err: %s.\n", err) + } +} + // Generic Minio initialization to create/load config, prepare loggers, etc.. func minioInit(ctx *cli.Context) { // Set global variables after parsing passed arguments @@ -174,43 +190,19 @@ func minioInit(ctx *cli.Context) { // Is TLS configured?. globalIsSSL = isSSL() - // Migrate any old version of config / state files to newer format. - migrate() - - // Initialize config. - configCreated, err := initConfig() - if err != nil { - console.Fatalf("Unable to initialize minio config. Err: %s.\n", err) - } - if configCreated { - console.Println("Created minio configuration file at " + mustGetConfigPath()) - } + // Initialize minio server config. + initConfig() // Enable all loggers by now so we can use errorIf() and fatalIf() enableLoggers() - // Fetch access keys from environment variables and update the config. - if globalEnvAccessKey != "" && globalEnvSecretKey != "" { - // Set new credentials. - serverConfig.SetCredential(credential{ - AccessKey: globalEnvAccessKey, - SecretKey: globalEnvSecretKey, - }) - } - if !isAccessKeyValid(serverConfig.GetCredential().AccessKey) { - fatalIf(errInvalidArgument, "Invalid access key. Accept only a string starting with a alphabetic and containing from 5 to 20 characters.") - } - if !isSecretKeyValid(serverConfig.GetCredential().SecretKey) { - fatalIf(errInvalidArgument, "Invalid secret key. Accept only a string containing from 8 to 40 characters.") - } - // Init the error tracing module. initError() } // Main main for minio server. -func Main() { +func Main(args []string, exitFn func(int)) { app := registerApp() app.Before = func(c *cli.Context) error { // Valid input arguments to main. @@ -224,5 +216,7 @@ func Main() { } // Run the app - exit on error. - app.RunAndExitOnError() + if err := app.Run(args); err != nil { + exitFn(1) + } } diff --git a/cmd/notifier-config.go b/cmd/notifier-config.go new file mode 100644 index 000000000..2c9728158 --- /dev/null +++ b/cmd/notifier-config.go @@ -0,0 +1,228 @@ +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmd + +import "sync" + +// Notifier represents collection of supported notification queues. +type notifier struct { + sync.RWMutex + AMQP amqpConfigs `json:"amqp"` + NATS natsConfigs `json:"nats"` + ElasticSearch elasticSearchConfigs `json:"elasticsearch"` + Redis redisConfigs `json:"redis"` + PostgreSQL postgreSQLConfigs `json:"postgresql"` + Kafka kafkaConfigs `json:"kafka"` + Webhook webhookConfigs `json:"webhook"` + // Add new notification queues. +} + +type amqpConfigs map[string]amqpNotify + +func (a amqpConfigs) Clone() amqpConfigs { + a2 := make(amqpConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +type natsConfigs map[string]natsNotify + +func (a natsConfigs) Clone() natsConfigs { + a2 := make(natsConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +type elasticSearchConfigs map[string]elasticSearchNotify + +func (a elasticSearchConfigs) Clone() elasticSearchConfigs { + a2 := make(elasticSearchConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +type redisConfigs map[string]redisNotify + +func (a redisConfigs) Clone() redisConfigs { + a2 := make(redisConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +type postgreSQLConfigs map[string]postgreSQLNotify + +func (a postgreSQLConfigs) Clone() postgreSQLConfigs { + a2 := make(postgreSQLConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +type kafkaConfigs map[string]kafkaNotify + +func (a kafkaConfigs) Clone() kafkaConfigs { + a2 := make(kafkaConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +type webhookConfigs map[string]webhookNotify + +func (a webhookConfigs) Clone() webhookConfigs { + a2 := make(webhookConfigs, len(a)) + for k, v := range a { + a2[k] = v + } + return a2 +} + +func (n *notifier) SetAMQPByID(accountID string, amqpn amqpNotify) { + n.Lock() + defer n.Unlock() + n.AMQP[accountID] = amqpn +} + +func (n *notifier) GetAMQP() map[string]amqpNotify { + n.RLock() + defer n.RUnlock() + return n.AMQP.Clone() +} + +func (n *notifier) GetAMQPByID(accountID string) amqpNotify { + n.RLock() + defer n.RUnlock() + return n.AMQP[accountID] +} + +func (n *notifier) SetNATSByID(accountID string, natsn natsNotify) { + n.Lock() + defer n.Unlock() + n.NATS[accountID] = natsn +} + +func (n *notifier) GetNATS() map[string]natsNotify { + n.RLock() + defer n.RUnlock() + return n.NATS.Clone() +} + +func (n *notifier) GetNATSByID(accountID string) natsNotify { + n.RLock() + defer n.RUnlock() + return n.NATS[accountID] +} + +func (n *notifier) SetElasticSearchByID(accountID string, es elasticSearchNotify) { + n.Lock() + defer n.Unlock() + n.ElasticSearch[accountID] = es +} + +func (n *notifier) GetElasticSearchByID(accountID string) elasticSearchNotify { + n.RLock() + defer n.RUnlock() + return n.ElasticSearch[accountID] +} + +func (n *notifier) GetElasticSearch() map[string]elasticSearchNotify { + n.RLock() + defer n.RUnlock() + return n.ElasticSearch.Clone() +} + +func (n *notifier) SetRedisByID(accountID string, r redisNotify) { + n.Lock() + defer n.Unlock() + n.Redis[accountID] = r +} + +func (n *notifier) GetRedis() map[string]redisNotify { + n.RLock() + defer n.RUnlock() + return n.Redis.Clone() +} + +func (n *notifier) GetRedisByID(accountID string) redisNotify { + n.RLock() + defer n.RUnlock() + return n.Redis[accountID] +} + +func (n *notifier) GetWebhook() map[string]webhookNotify { + n.RLock() + defer n.RUnlock() + return n.Webhook.Clone() +} + +func (n *notifier) GetWebhookByID(accountID string) webhookNotify { + n.RLock() + defer n.RUnlock() + return n.Webhook[accountID] +} + +func (n *notifier) SetWebhookByID(accountID string, pgn webhookNotify) { + n.Lock() + defer n.Unlock() + n.Webhook[accountID] = pgn +} + +func (n *notifier) SetPostgreSQLByID(accountID string, pgn postgreSQLNotify) { + n.Lock() + defer n.Unlock() + n.PostgreSQL[accountID] = pgn +} + +func (n *notifier) GetPostgreSQL() map[string]postgreSQLNotify { + n.RLock() + defer n.RUnlock() + return n.PostgreSQL.Clone() +} + +func (n *notifier) GetPostgreSQLByID(accountID string) postgreSQLNotify { + n.RLock() + defer n.RUnlock() + return n.PostgreSQL[accountID] +} + +func (n *notifier) SetKafkaByID(accountID string, kn kafkaNotify) { + n.Lock() + defer n.Unlock() + n.Kafka[accountID] = kn +} + +func (n *notifier) GetKafka() map[string]kafkaNotify { + n.RLock() + defer n.RUnlock() + return n.Kafka.Clone() +} + +func (n *notifier) GetKafkaByID(accountID string) kafkaNotify { + n.RLock() + defer n.RUnlock() + return n.Kafka[accountID] +} diff --git a/vendor/github.com/minio/blake2b-simd/compress_noasm.go b/cmd/notifier-config_test.go similarity index 78% rename from vendor/github.com/minio/blake2b-simd/compress_noasm.go rename to cmd/notifier-config_test.go index d3c675847..a416825a9 100644 --- a/vendor/github.com/minio/blake2b-simd/compress_noasm.go +++ b/cmd/notifier-config_test.go @@ -1,7 +1,5 @@ -//+build !amd64 noasm appengine - /* - * Minio Cloud Storage, (C) 2016 Minio, Inc. + * Minio Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +14,4 @@ * limitations under the License. */ -package blake2b - -func compress(d *digest, p []uint8) { - compressGeneric(d, p) -} +package cmd diff --git a/cmd/notifiers.go b/cmd/notifiers.go index b7b5ec496..1d3ed1bfd 100644 --- a/cmd/notifiers.go +++ b/cmd/notifiers.go @@ -18,7 +18,6 @@ package cmd import ( "errors" - "strings" "github.com/minio/minio/pkg/wildcard" ) @@ -55,24 +54,12 @@ const ( var errNotifyNotEnabled = errors.New("requested notifier not enabled") -// Notifier represents collection of supported notification queues. -type notifier struct { - AMQP map[string]amqpNotify `json:"amqp"` - NATS map[string]natsNotify `json:"nats"` - ElasticSearch map[string]elasticSearchNotify `json:"elasticsearch"` - Redis map[string]redisNotify `json:"redis"` - PostgreSQL map[string]postgreSQLNotify `json:"postgresql"` - Kafka map[string]kafkaNotify `json:"kafka"` - Webhook map[string]webhookNotify `json:"webhook"` - // Add new notification queues. -} - // Returns true if queueArn is for an AMQP queue. func isAMQPQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypeAMQP { return false } - amqpL := serverConfig.GetAMQPNotifyByID(sqsArn.AccountID) + amqpL := serverConfig.Notify.GetAMQPByID(sqsArn.AccountID) if !amqpL.Enable { return false } @@ -91,7 +78,7 @@ func isNATSQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypeNATS { return false } - natsL := serverConfig.GetNATSNotifyByID(sqsArn.AccountID) + natsL := serverConfig.Notify.GetNATSByID(sqsArn.AccountID) if !natsL.Enable { return false } @@ -110,7 +97,7 @@ func isWebhookQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypeWebhook { return false } - rNotify := serverConfig.GetWebhookNotifyByID(sqsArn.AccountID) + rNotify := serverConfig.Notify.GetWebhookByID(sqsArn.AccountID) if !rNotify.Enable { return false } @@ -122,7 +109,7 @@ func isRedisQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypeRedis { return false } - rNotify := serverConfig.GetRedisNotifyByID(sqsArn.AccountID) + rNotify := serverConfig.Notify.GetRedisByID(sqsArn.AccountID) if !rNotify.Enable { return false } @@ -141,7 +128,7 @@ func isElasticQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypeElastic { return false } - esNotify := serverConfig.GetElasticSearchNotifyByID(sqsArn.AccountID) + esNotify := serverConfig.Notify.GetElasticSearchByID(sqsArn.AccountID) if !esNotify.Enable { return false } @@ -159,7 +146,7 @@ func isPostgreSQLQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypePostgreSQL { return false } - pgNotify := serverConfig.GetPostgreSQLNotifyByID(sqsArn.AccountID) + pgNotify := serverConfig.Notify.GetPostgreSQLByID(sqsArn.AccountID) if !pgNotify.Enable { return false } @@ -177,7 +164,7 @@ func isKafkaQueue(sqsArn arnSQS) bool { if sqsArn.Type != queueTypeKafka { return false } - kafkaNotifyCfg := serverConfig.GetKafkaNotifyByID(sqsArn.AccountID) + kafkaNotifyCfg := serverConfig.Notify.GetKafkaByID(sqsArn.AccountID) if !kafkaNotifyCfg.Enable { return false } @@ -206,9 +193,9 @@ func filterRuleMatch(object string, frs []filterRule) bool { var prefixMatch, suffixMatch = true, true for _, fr := range frs { if isValidFilterNamePrefix(fr.Name) { - prefixMatch = strings.HasPrefix(object, fr.Value) + prefixMatch = hasPrefix(object, fr.Value) } else if isValidFilterNameSuffix(fr.Name) { - suffixMatch = strings.HasSuffix(object, fr.Value) + suffixMatch = hasSuffix(object, fr.Value) } } return prefixMatch && suffixMatch diff --git a/cmd/notify-amqp.go b/cmd/notify-amqp.go index a5b87f72d..9168cc959 100644 --- a/cmd/notify-amqp.go +++ b/cmd/notify-amqp.go @@ -59,7 +59,7 @@ func dialAMQP(amqpL amqpNotify) (amqpConn, error) { } func newAMQPNotify(accountID string) (*logrus.Logger, error) { - amqpL := serverConfig.GetAMQPNotifyByID(accountID) + amqpL := serverConfig.Notify.GetAMQPByID(accountID) // Connect to amqp server. amqpC, err := dialAMQP(amqpL) diff --git a/cmd/notify-elasticsearch.go b/cmd/notify-elasticsearch.go index 98249d16d..508b7ed9e 100644 --- a/cmd/notify-elasticsearch.go +++ b/cmd/notify-elasticsearch.go @@ -55,7 +55,7 @@ func dialElastic(esNotify elasticSearchNotify) (*elastic.Client, error) { } func newElasticNotify(accountID string) (*logrus.Logger, error) { - esNotify := serverConfig.GetElasticSearchNotifyByID(accountID) + esNotify := serverConfig.Notify.GetElasticSearchByID(accountID) // Dial to elastic search. client, err := dialElastic(esNotify) diff --git a/cmd/notify-kafka.go b/cmd/notify-kafka.go index d6e5d1f66..7ddf454b8 100644 --- a/cmd/notify-kafka.go +++ b/cmd/notify-kafka.go @@ -75,7 +75,7 @@ func dialKafka(kn kafkaNotify) (kafkaConn, error) { } func newKafkaNotify(accountID string) (*logrus.Logger, error) { - kafkaNotifyCfg := serverConfig.GetKafkaNotifyByID(accountID) + kafkaNotifyCfg := serverConfig.Notify.GetKafkaByID(accountID) // Try connecting to the configured Kafka broker(s). kc, err := dialKafka(kafkaNotifyCfg) diff --git a/cmd/notify-nats.go b/cmd/notify-nats.go index bec7cdcdf..b18751ded 100644 --- a/cmd/notify-nats.go +++ b/cmd/notify-nats.go @@ -127,7 +127,7 @@ func closeNATS(conn natsIOConn) { } func newNATSNotify(accountID string) (*logrus.Logger, error) { - natsL := serverConfig.GetNATSNotifyByID(accountID) + natsL := serverConfig.Notify.GetNATSByID(accountID) // Connect to nats server. natsC, err := dialNATS(natsL, false) diff --git a/cmd/notify-postgresql.go b/cmd/notify-postgresql.go index 5e1634655..116092520 100644 --- a/cmd/notify-postgresql.go +++ b/cmd/notify-postgresql.go @@ -174,7 +174,7 @@ func dialPostgreSQL(pgN postgreSQLNotify) (pgConn, error) { } func newPostgreSQLNotify(accountID string) (*logrus.Logger, error) { - pgNotify := serverConfig.GetPostgreSQLNotifyByID(accountID) + pgNotify := serverConfig.Notify.GetPostgreSQLByID(accountID) // Dial postgres pgC, err := dialPostgreSQL(pgNotify) diff --git a/cmd/notify-redis.go b/cmd/notify-redis.go index f44333cca..8e382edb5 100644 --- a/cmd/notify-redis.go +++ b/cmd/notify-redis.go @@ -83,7 +83,7 @@ func dialRedis(rNotify redisNotify) (*redis.Pool, error) { } func newRedisNotify(accountID string) (*logrus.Logger, error) { - rNotify := serverConfig.GetRedisNotifyByID(accountID) + rNotify := serverConfig.Notify.GetRedisByID(accountID) // Dial redis. rPool, err := dialRedis(rNotify) diff --git a/cmd/notify-webhook.go b/cmd/notify-webhook.go index 95af0fcb4..7bdb8f086 100644 --- a/cmd/notify-webhook.go +++ b/cmd/notify-webhook.go @@ -52,7 +52,7 @@ func lookupEndpoint(u *url.URL) error { // Initializes new webhook logrus notifier. func newWebhookNotify(accountID string) (*logrus.Logger, error) { - rNotify := serverConfig.GetWebhookNotifyByID(accountID) + rNotify := serverConfig.Notify.GetWebhookByID(accountID) if rNotify.Endpoint == "" { return nil, errInvalidArgument @@ -119,6 +119,9 @@ func (n httpConn) Fire(entry *logrus.Entry) error { return err } + // Make sure to close the response body so the connection can be re-used. + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted && resp.StatusCode != http.StatusContinue { diff --git a/cmd/notify-webhook_test.go b/cmd/notify-webhook_test.go index 4740901f0..ff974f751 100644 --- a/cmd/notify-webhook_test.go +++ b/cmd/notify-webhook_test.go @@ -51,13 +51,13 @@ func TestNewWebHookNotify(t *testing.T) { t.Fatal("Unexpected should fail") } - serverConfig.SetWebhookNotifyByID("10", webhookNotify{Enable: true, Endpoint: "http://www."}) + serverConfig.Notify.SetWebhookByID("10", webhookNotify{Enable: true, Endpoint: "http://www."}) _, err = newWebhookNotify("10") if err == nil { t.Fatal("Unexpected should fail with lookupHost") } - serverConfig.SetWebhookNotifyByID("15", webhookNotify{Enable: true, Endpoint: "http://%"}) + serverConfig.Notify.SetWebhookByID("15", webhookNotify{Enable: true, Endpoint: "http://%"}) _, err = newWebhookNotify("15") if err == nil { t.Fatal("Unexpected should fail with invalid URL escape") @@ -66,7 +66,7 @@ func TestNewWebHookNotify(t *testing.T) { server := httptest.NewServer(postHandler{}) defer server.Close() - serverConfig.SetWebhookNotifyByID("20", webhookNotify{Enable: true, Endpoint: server.URL}) + serverConfig.Notify.SetWebhookByID("20", webhookNotify{Enable: true, Endpoint: server.URL}) webhook, err := newWebhookNotify("20") if err != nil { t.Fatal("Unexpected shouldn't fail", err) diff --git a/cmd/object-api-common_test.go b/cmd/object-api-common_test.go index d312901c5..784044088 100644 --- a/cmd/object-api-common_test.go +++ b/cmd/object-api-common_test.go @@ -116,8 +116,8 @@ func TestGetPath(t *testing.T) { {"D:\\", "d:\\"}, {"D:", "d:"}, {"\\", "\\"}, - {"http://localhost/d:/export", "d:/export"}, - {"https://localhost/d:/export", "d:/export"}, + {"http://127.0.0.1/d:/export", "d:/export"}, + {"https://127.0.0.1/d:/export", "d:/export"}, } } else { testCases = []struct { @@ -125,8 +125,8 @@ func TestGetPath(t *testing.T) { path string }{ {"/export", "/export"}, - {"http://localhost/export", "/export"}, - {"https://localhost/export", "/export"}, + {"http://127.0.0.1/export", "/export"}, + {"https://127.0.0.1/export", "/export"}, } } testCasesCommon := []struct { diff --git a/cmd/object-api-datatypes.go b/cmd/object-api-datatypes.go index 0da114699..307220f4d 100644 --- a/cmd/object-api-datatypes.go +++ b/cmd/object-api-datatypes.go @@ -26,8 +26,8 @@ const ( Unknown BackendType = iota // Filesystem backend. FS - // Multi disk XL (single, distributed) backend. - XL + // Multi disk Erasure (single, distributed) backend. + Erasure // Add your own backend. ) @@ -39,10 +39,10 @@ type StorageInfo struct { Free int64 // Backend type. Backend struct { - // Represents various backend types, currently on FS and XL. + // Represents various backend types, currently on FS and Erasure. Type BackendType - // Following fields are only meaningful if BackendType is XL. + // Following fields are only meaningful if BackendType is Erasure. OnlineDisks int // Online disks during server startup. OfflineDisks int // Offline disks during server startup. ReadQuorum int // Minimum disks required for successful read operations. @@ -145,7 +145,7 @@ type ListPartsInfo struct { IsTruncated bool // List of all parts. - Parts []partInfo + Parts []PartInfo EncodingType string // Not supported yet. } @@ -220,8 +220,8 @@ type ListObjectsInfo struct { Prefixes []string } -// partInfo - represents individual part metadata. -type partInfo struct { +// PartInfo - represents individual part metadata. +type PartInfo struct { // Part number that identifies the part. This is a positive integer between // 1 and 10,000. PartNumber int diff --git a/cmd/object-api-input-checks.go b/cmd/object-api-input-checks.go index 74b736e54..62e77ab16 100644 --- a/cmd/object-api-input-checks.go +++ b/cmd/object-api-input-checks.go @@ -16,11 +16,7 @@ package cmd -import ( - "strings" - - "github.com/skyrings/skyring-common/tools/uuid" -) +import "github.com/skyrings/skyring-common/tools/uuid" // Checks on GetObject arguments, bucket and object. func checkGetObjArgs(bucket, object string) error { @@ -69,7 +65,7 @@ func checkListObjsArgs(bucket, prefix, marker, delimiter string, obj ObjectLayer }) } // Verify if marker has prefix. - if marker != "" && !strings.HasPrefix(marker, prefix) { + if marker != "" && !hasPrefix(marker, prefix) { return traceError(InvalidMarkerPrefixCombination{ Marker: marker, Prefix: prefix, @@ -84,7 +80,7 @@ func checkListMultipartArgs(bucket, prefix, keyMarker, uploadIDMarker, delimiter return err } if uploadIDMarker != "" { - if strings.HasSuffix(keyMarker, slashSeparator) { + if hasSuffix(keyMarker, slashSeparator) { return traceError(InvalidUploadIDKeyCombination{ UploadIDMarker: uploadIDMarker, KeyMarker: keyMarker, diff --git a/cmd/object-api-interface.go b/cmd/object-api-interface.go index 6687d9594..4938af274 100644 --- a/cmd/object-api-interface.go +++ b/cmd/object-api-interface.go @@ -41,7 +41,8 @@ type ObjectLayer interface { // Multipart operations. ListMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (result ListMultipartsInfo, err error) NewMultipartUpload(bucket, object string, metadata map[string]string) (uploadID string, err error) - PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (md5 string, err error) + CopyObjectPart(srcBucket, srcObject, destBucket, destObject string, uploadID string, partID int, startOffset int64, length int64) (info PartInfo, err error) + PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (info PartInfo, err error) ListObjectParts(bucket, object, uploadID string, partNumberMarker int, maxParts int) (result ListPartsInfo, err error) AbortMultipartUpload(bucket, object, uploadID string) error CompleteMultipartUpload(bucket, object, uploadID string, uploadedParts []completePart) (objInfo ObjectInfo, err error) diff --git a/cmd/object-api-multipart-common.go b/cmd/object-api-multipart-common.go index b515d5b5e..5540e6a43 100644 --- a/cmd/object-api-multipart-common.go +++ b/cmd/object-api-multipart-common.go @@ -22,7 +22,6 @@ import ( "io/ioutil" "path" "sort" - "sync" "time" "github.com/minio/minio/pkg/lock" @@ -76,26 +75,30 @@ func (u *uploadsV1) IsEmpty() bool { return len(u.Uploads) == 0 } -func (u *uploadsV1) WriteTo(writer io.Writer) (n int64, err error) { +func (u *uploadsV1) WriteTo(lk *lock.LockedFile) (n int64, err error) { // Serialize to prepare to write to disk. var uplBytes []byte uplBytes, err = json.Marshal(u) if err != nil { return 0, traceError(err) } - if err = writer.(*lock.LockedFile).Truncate(0); err != nil { + if err = lk.Truncate(0); err != nil { return 0, traceError(err) } - _, err = writer.Write(uplBytes) + _, err = lk.Write(uplBytes) if err != nil { return 0, traceError(err) } return int64(len(uplBytes)), nil } -func (u *uploadsV1) ReadFrom(reader io.Reader) (n int64, err error) { +func (u *uploadsV1) ReadFrom(lk *lock.LockedFile) (n int64, err error) { var uploadIDBytes []byte - uploadIDBytes, err = ioutil.ReadAll(reader) + fi, err := lk.Stat() + if err != nil { + return 0, traceError(err) + } + uploadIDBytes, err = ioutil.ReadAll(io.NewSectionReader(lk, 0, fi.Size())) if err != nil { return 0, traceError(err) } @@ -157,45 +160,6 @@ func writeUploadJSON(u *uploadsV1, uploadsPath, tmpPath string, disk StorageAPI) return nil } -// Wrapper which removes all the uploaded parts. -func cleanupUploadedParts(bucket, object, uploadID string, storageDisks ...StorageAPI) error { - var errs = make([]error, len(storageDisks)) - var wg = &sync.WaitGroup{} - - // Construct uploadIDPath. - uploadIDPath := path.Join(bucket, object, uploadID) - - // Cleanup uploadID for all disks. - for index, disk := range storageDisks { - if disk == nil { - errs[index] = traceError(errDiskNotFound) - continue - } - wg.Add(1) - // Cleanup each uploadID in a routine. - go func(index int, disk StorageAPI) { - defer wg.Done() - err := cleanupDir(disk, minioMetaMultipartBucket, uploadIDPath) - if err != nil { - errs[index] = err - return - } - errs[index] = nil - }(index, disk) - } - - // Wait for all the cleanups to finish. - wg.Wait() - - // Return first error. - for _, err := range errs { - if err != nil { - return err - } - } - return nil -} - // listMultipartUploadIDs - list all the upload ids from a marker up to 'count'. func listMultipartUploadIDs(bucketName, objectName, uploadIDMarker string, count int, disk StorageAPI) ([]uploadMetadata, bool, error) { var uploads []uploadMetadata diff --git a/cmd/object-api-multipart_test.go b/cmd/object-api-multipart_test.go index 5e0146f3e..5feee0363 100644 --- a/cmd/object-api-multipart_test.go +++ b/cmd/object-api-multipart_test.go @@ -346,7 +346,7 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH // Validate all the test cases. for i, testCase := range testCases { - actualMd5Hex, actualErr := obj.PutObjectPart(testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, testCase.intputDataSize, bytes.NewBufferString(testCase.inputReaderData), testCase.inputMd5, testCase.inputSHA256) + actualInfo, actualErr := obj.PutObjectPart(testCase.bucketName, testCase.objName, testCase.uploadID, testCase.PartID, testCase.intputDataSize, bytes.NewBufferString(testCase.inputReaderData), testCase.inputMd5, testCase.inputSHA256) // All are test cases above are expected to fail. if actualErr != nil && testCase.shouldPass { t.Errorf("Test %d: %s: Expected to pass, but failed with: %s.", i+1, instanceType, actualErr.Error()) @@ -363,8 +363,8 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH // Test passes as expected, but the output values are verified for correctness here. if actualErr == nil && testCase.shouldPass { // Asserting whether the md5 output is correct. - if testCase.inputMd5 != actualMd5Hex { - t.Errorf("Test %d: %s: Calculated Md5 different from the actual one %s.", i+1, instanceType, actualMd5Hex) + if testCase.inputMd5 != actualInfo.ETag { + t.Errorf("Test %d: %s: Calculated Md5 different from the actual one %s.", i+1, instanceType, actualInfo.ETag) } } } @@ -1344,7 +1344,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks Object: objectNames[0], MaxParts: 10, UploadID: uploadIDs[0], - Parts: []partInfo{ + Parts: []PartInfo{ { PartNumber: 1, Size: 4, @@ -1375,7 +1375,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks NextPartNumberMarker: 3, IsTruncated: true, UploadID: uploadIDs[0], - Parts: []partInfo{ + Parts: []PartInfo{ { PartNumber: 1, Size: 4, @@ -1400,7 +1400,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks MaxParts: 2, IsTruncated: false, UploadID: uploadIDs[0], - Parts: []partInfo{ + Parts: []PartInfo{ { PartNumber: 4, Size: 4, @@ -1581,7 +1581,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler) Object: objectNames[0], MaxParts: 10, UploadID: uploadIDs[0], - Parts: []partInfo{ + Parts: []PartInfo{ { PartNumber: 1, Size: 4, @@ -1612,7 +1612,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler) NextPartNumberMarker: 3, IsTruncated: true, UploadID: uploadIDs[0], - Parts: []partInfo{ + Parts: []PartInfo{ { PartNumber: 1, Size: 4, @@ -1637,7 +1637,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler) MaxParts: 2, IsTruncated: false, UploadID: uploadIDs[0], - Parts: []partInfo{ + Parts: []PartInfo{ { PartNumber: 4, Size: 4, diff --git a/cmd/object-api-utils.go b/cmd/object-api-utils.go index 95f63d339..206c0c1a0 100644 --- a/cmd/object-api-utils.go +++ b/cmd/object-api-utils.go @@ -22,6 +22,7 @@ import ( "io" "path" "regexp" + "runtime" "strings" "unicode/utf8" @@ -91,10 +92,10 @@ func IsValidObjectName(object string) bool { if len(object) == 0 { return false } - if strings.HasSuffix(object, slashSeparator) { + if hasSuffix(object, slashSeparator) { return false } - if strings.HasPrefix(object, slashSeparator) { + if hasPrefix(object, slashSeparator) { return false } return IsValidObjectPrefix(object) @@ -159,6 +160,26 @@ func getCompleteMultipartMD5(parts []completePart) (string, error) { return s3MD5, nil } +// Prefix matcher string matches prefix in a platform specific way. +// For example on windows since its case insensitive we are supposed +// to do case insensitive checks. +func hasPrefix(s string, prefix string) bool { + if runtime.GOOS == "windows" { + return strings.HasPrefix(strings.ToLower(s), strings.ToLower(prefix)) + } + return strings.HasPrefix(s, prefix) +} + +// Suffix matcher string matches suffix in a platform specific way. +// For example on windows since its case insensitive we are supposed +// to do case insensitive checks. +func hasSuffix(s string, suffix string) bool { + if runtime.GOOS == "windows" { + return strings.HasSuffix(strings.ToLower(s), strings.ToLower(suffix)) + } + return strings.HasSuffix(s, suffix) +} + // byBucketName is a collection satisfying sort.Interface. type byBucketName []BucketInfo diff --git a/cmd/object-handlers-common.go b/cmd/object-handlers-common.go index 46fbe1ec8..dee33a0d5 100644 --- a/cmd/object-handlers-common.go +++ b/cmd/object-handlers-common.go @@ -22,6 +22,16 @@ import ( "time" ) +// Validates the preconditions for CopyObjectPart, returns true if CopyObjectPart +// operation should not proceed. Preconditions supported are: +// x-amz-copy-source-if-modified-since +// x-amz-copy-source-if-unmodified-since +// x-amz-copy-source-if-match +// x-amz-copy-source-if-none-match +func checkCopyObjectPartPreconditions(w http.ResponseWriter, r *http.Request, objInfo ObjectInfo) bool { + return checkCopyObjectPreconditions(w, r, objInfo) +} + // Validates the preconditions for CopyObject, returns true if CopyObject operation should not proceed. // Preconditions supported are: // x-amz-copy-source-if-modified-since diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 73b10b32e..a3ef52f9f 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -56,10 +56,9 @@ func setGetRespHeaders(w http.ResponseWriter, reqParams url.Values) { func errAllowableObjectNotFound(bucket string, r *http.Request) APIErrorCode { if getRequestAuthType(r) == authTypeAnonymous { //we care about the bucket as a whole, not a particular resource - url := *r.URL - url.Path = "/" + bucket - - if s3Error := enforceBucketPolicy(bucket, "s3:ListBucket", &url); s3Error != ErrNone { + resource := "/" + bucket + if s3Error := enforceBucketPolicy(bucket, "s3:ListBucket", resource, + r.Referer(), r.URL.Query()); s3Error != ErrNone { return ErrAccessDenied } } @@ -440,7 +439,8 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req return case authTypeAnonymous: // http://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html - if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL); s3Error != ErrNone { + if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL.Path, + r.Referer(), r.URL.Query()); s3Error != ErrNone { writeErrorResponse(w, s3Error, r.URL) return } @@ -531,7 +531,117 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r writeSuccessResponseXML(w, encodedSuccessResponse) } -// PutObjectPartHandler - Upload part +// CopyObjectPartHandler - uploads a part by copying data from an existing object as data source. +func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + dstBucket := vars["bucket"] + dstObject := vars["object"] + + objectAPI := api.ObjectAPI() + if objectAPI == nil { + writeErrorResponse(w, ErrServerNotInitialized, r.URL) + return + } + + if s3Error := checkRequestAuthType(r, dstBucket, "s3:PutObject", serverConfig.GetRegion()); s3Error != ErrNone { + writeErrorResponse(w, s3Error, r.URL) + return + } + + // Copy source path. + cpSrcPath, err := url.QueryUnescape(r.Header.Get("X-Amz-Copy-Source")) + if err != nil { + // Save unescaped string as is. + cpSrcPath = r.Header.Get("X-Amz-Copy-Source") + } + + srcBucket, srcObject := path2BucketAndObject(cpSrcPath) + // If source object is empty or bucket is empty, reply back invalid copy source. + if srcObject == "" || srcBucket == "" { + writeErrorResponse(w, ErrInvalidCopySource, r.URL) + return + } + + uploadID := r.URL.Query().Get("uploadId") + partIDString := r.URL.Query().Get("partNumber") + + partID, err := strconv.Atoi(partIDString) + if err != nil { + writeErrorResponse(w, ErrInvalidPart, r.URL) + return + } + + // check partID with maximum part ID for multipart objects + if isMaxPartID(partID) { + writeErrorResponse(w, ErrInvalidMaxParts, r.URL) + return + } + + // Hold read locks on source object only if we are + // going to read data from source object. + objectSRLock := globalNSMutex.NewNSLock(srcBucket, srcObject) + objectSRLock.RLock() + defer objectSRLock.RUnlock() + + objInfo, err := objectAPI.GetObjectInfo(srcBucket, srcObject) + if err != nil { + errorIf(err, "Unable to fetch object info.") + writeErrorResponse(w, toAPIErrorCode(err), r.URL) + return + } + + // Get request range. + var hrange *httpRange + rangeHeader := r.Header.Get("x-amz-copy-source-range") + if rangeHeader != "" { + if hrange, err = parseRequestRange(rangeHeader, objInfo.Size); err != nil { + // Handle only errInvalidRange + // Ignore other parse error and treat it as regular Get request like Amazon S3. + if err == errInvalidRange { + writeErrorResponse(w, ErrInvalidRange, r.URL) + return + } + + // log the error. + errorIf(err, "Invalid request range") + } + } + + // Verify before x-amz-copy-source preconditions before continuing with CopyObject. + if checkCopyObjectPartPreconditions(w, r, objInfo) { + return + } + + // Get the object. + startOffset := int64(0) + length := objInfo.Size + if hrange != nil { + startOffset = hrange.offsetBegin + length = hrange.getLength() + } + + /// maximum copy size for multipart objects in a single operation + if isMaxObjectSize(length) { + writeErrorResponse(w, ErrEntityTooLarge, r.URL) + return + } + + // Copy source object to destination, if source and destination + // object is same then only metadata is updated. + partInfo, err := objectAPI.CopyObjectPart(srcBucket, srcObject, dstBucket, dstObject, uploadID, partID, startOffset, length) + if err != nil { + writeErrorResponse(w, toAPIErrorCode(err), r.URL) + return + } + + response := generateCopyObjectPartResponse(partInfo.ETag, partInfo.LastModified) + encodedSuccessResponse := encodeResponse(response) + + // Write success response. + writeSuccessResponseXML(w, encodedSuccessResponse) +} + +// PutObjectPartHandler - uploads an incoming part for an ongoing multipart operation. func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bucket := vars["bucket"] @@ -590,7 +700,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http return } - var partMD5 string + var partInfo PartInfo incomingMD5 := hex.EncodeToString(md5Bytes) sha256sum := "" switch rAuthType { @@ -600,12 +710,13 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http return case authTypeAnonymous: // http://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html - if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL); s3Error != ErrNone { + if s3Error := enforceBucketPolicy(bucket, "s3:PutObject", r.URL.Path, + r.Referer(), r.URL.Query()); s3Error != ErrNone { writeErrorResponse(w, s3Error, r.URL) return } // No need to verify signature, anonymous request access is already allowed. - partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum) + partInfo, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum) case authTypeStreamingSigned: // Initialize stream signature verifier. reader, s3Error := newSignV4ChunkedReader(r) @@ -614,7 +725,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http writeErrorResponse(w, s3Error, r.URL) return } - partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, incomingMD5, sha256sum) + partInfo, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, incomingMD5, sha256sum) case authTypeSignedV2, authTypePresignedV2: s3Error := isReqAuthenticatedV2(r) if s3Error != ErrNone { @@ -622,7 +733,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http writeErrorResponse(w, s3Error, r.URL) return } - partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum) + partInfo, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum) case authTypePresigned, authTypeSigned: if s3Error := reqSignatureV4Verify(r); s3Error != ErrNone { errorIf(errSignatureMismatch, dumpRequest(r)) @@ -633,7 +744,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http if !skipContentSha256Cksum(r) { sha256sum = r.Header.Get("X-Amz-Content-Sha256") } - partMD5, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum) + partInfo, err = objectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, incomingMD5, sha256sum) } if err != nil { errorIf(err, "Unable to create object part.") @@ -641,8 +752,8 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http writeErrorResponse(w, toAPIErrorCode(err), r.URL) return } - if partMD5 != "" { - w.Header().Set("ETag", "\""+partMD5+"\"") + if partInfo.ETag != "" { + w.Header().Set("ETag", "\""+partInfo.ETag+"\"") } writeSuccessResponseHeadersOnly(w) diff --git a/cmd/object-handlers_test.go b/cmd/object-handlers_test.go index ed454fd87..95e126202 100644 --- a/cmd/object-handlers_test.go +++ b/cmd/object-handlers_test.go @@ -489,6 +489,20 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam shouldPass: true, }, // Test case - 3 + // Empty data + { + bucketName: bucketName, + objectName: objectName, + data: []byte{}, + dataLen: 0, + chunkSize: 64 * humanize.KiByte, + expectedContent: []byte{}, + expectedRespStatus: http.StatusOK, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + shouldPass: true, + }, + // Test case - 4 // Invalid access key id. { bucketName: bucketName, @@ -502,7 +516,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam secretKey: "", shouldPass: false, }, - // Test case - 4 + // Test case - 5 // Wrong auth header returns as bad request. { bucketName: bucketName, @@ -517,7 +531,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam shouldPass: false, removeAuthHeader: true, }, - // Test case - 5 + // Test case - 6 // Large chunk size.. also passes. { bucketName: bucketName, @@ -531,7 +545,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam secretKey: credentials.SecretKey, shouldPass: false, }, - // Test case - 6 + // Test case - 7 // Chunk with malformed encoding. { bucketName: bucketName, @@ -546,7 +560,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam shouldPass: false, fault: malformedEncoding, }, - // Test case - 7 + // Test case - 8 // Chunk with shorter than advertised chunk data. { bucketName: bucketName, @@ -561,7 +575,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam shouldPass: false, fault: unexpectedEOF, }, - // Test case - 8 + // Test case - 9 // Chunk with first chunk data byte tampered. { bucketName: bucketName, @@ -576,7 +590,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam shouldPass: false, fault: signatureMismatch, }, - // Test case - 9 + // Test case - 10 // Different date (timestamps) used in seed signature calculation // and chunks signature calculation. { @@ -592,7 +606,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam shouldPass: false, fault: chunkDateMismatch, }, - // Test case - 10 + // Test case - 11 // Set x-amz-decoded-content-length to a value too big to hold in int64. { bucketName: bucketName, @@ -669,11 +683,11 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam } buffer := new(bytes.Buffer) - err = obj.GetObject(testCase.bucketName, testCase.objectName, 0, int64(bytesDataLen), buffer) + err = obj.GetObject(testCase.bucketName, testCase.objectName, 0, int64(testCase.dataLen), buffer) if err != nil { t.Fatalf("Test %d: %s: Failed to fetch the copied object: %s", i+1, instanceType, err) } - if !bytes.Equal(bytesData, buffer.Bytes()) { + if !bytes.Equal(testCase.data, buffer.Bytes()) { t.Errorf("Test %d: %s: Data Mismatch: Data fetched back from the uploaded object doesn't match the original one.", i+1, instanceType) } buffer.Reset() @@ -918,6 +932,324 @@ func testAPIPutObjectHandler(obj ObjectLayer, instanceType, bucketName string, a } +// Wrapper for calling Copy Object Part API handler tests for both XL multiple disks and single node setup. +func TestAPICopyObjectPartHandler(t *testing.T) { + defer DetectTestLeak(t)() + ExecObjectLayerAPITest(t, testAPICopyObjectPartHandler, []string{"CopyObjectPart"}) +} + +func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName string, apiRouter http.Handler, + credentials credential, t *testing.T) { + + objectName := "test-object" + // register event notifier. + err := initEventNotifier(obj) + if err != nil { + t.Fatalf("Initializing event notifiers failed") + } + + // set of byte data for PutObject. + // object has to be created before running tests for Copy Object. + // this is required even to assert the copied object, + bytesData := []struct { + byteData []byte + }{ + {generateBytesData(6 * humanize.KiByte)}, + } + + // set of inputs for uploading the objects before tests for downloading is done. + putObjectInputs := []struct { + bucketName string + objectName string + contentLength int64 + textData []byte + metaData map[string]string + }{ + // case - 1. + {bucketName, objectName, int64(len(bytesData[0].byteData)), bytesData[0].byteData, make(map[string]string)}, + } + sha256sum := "" + // iterate through the above set of inputs and upload the object. + for i, input := range putObjectInputs { + // uploading the object. + _, err = obj.PutObject(input.bucketName, input.objectName, input.contentLength, bytes.NewBuffer(input.textData), input.metaData, sha256sum) + // if object upload fails stop the test. + if err != nil { + t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) + } + } + + // Initiate Multipart upload for testing PutObjectPartHandler. + testObject := "testobject" + + // PutObjectPart API HTTP Handler has to be tested in isolation, + // that is without any other handler being registered, + // That's why NewMultipartUpload is initiated using ObjectLayer. + uploadID, err := obj.NewMultipartUpload(bucketName, testObject, nil) + if err != nil { + // Failed to create NewMultipartUpload, abort. + t.Fatalf("Minio %s : %s", instanceType, err) + } + + // test cases with inputs and expected result for Copy Object. + testCases := []struct { + bucketName string + copySourceHeader string // data for "X-Amz-Copy-Source" header. Contains the object to be copied in the URL. + copySourceRange string // data for "X-Amz-Copy-Source-Range" header, contains the byte range offsets of data to be copied. + uploadID string // uploadID of the transaction. + invalidPartNumber bool // Sets an invalid multipart. + maximumPartNumber bool // Sets a maximum parts. + accessKey string + secretKey string + // expected output. + expectedRespStatus int + }{ + // Test case - 1, copy part 1 from from newObject1, ignore request headers. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + expectedRespStatus: http.StatusOK, + }, + + // Test case - 2. + // Test case with invalid source object. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/"), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusBadRequest, + }, + + // Test case - 3. + // Test case with new object name is same as object to be copied. + // Fail with file not found. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + testObject), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusNotFound, + }, + + // Test case - 4. + // Test case with valid byte range. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + copySourceRange: "bytes=500-4096", + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusOK, + }, + + // Test case - 5. + // Test case with invalid byte range. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + copySourceRange: "bytes=6145-", + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusRequestedRangeNotSatisfiable, + }, + + // Test case - 6. + // Test case with object name missing from source. + // fail with BadRequest. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("//123"), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusBadRequest, + }, + + // Test case - 7. + // Test case with non-existent source file. + // Case for the purpose of failing `api.ObjectAPI.GetObjectInfo`. + // Expecting the response status code to http.StatusNotFound (404). + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + "non-existent-object"), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusNotFound, + }, + + // Test case - 8. + // Test case with non-existent source file. + // Case for the purpose of failing `api.ObjectAPI.PutObjectPart`. + // Expecting the response status code to http.StatusNotFound (404). + { + bucketName: "non-existent-destination-bucket", + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusNotFound, + }, + + // Test case - 9. + // Case with invalid AccessKey. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + accessKey: "Invalid-AccessID", + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusForbidden, + }, + + // Test case - 10. + // Case with non-existent upload id. + { + bucketName: bucketName, + uploadID: "-1", + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + + expectedRespStatus: http.StatusNotFound, + }, + // Test case - 11. + // invalid part number. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + invalidPartNumber: true, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + expectedRespStatus: http.StatusOK, + }, + // Test case - 12. + // maximum part number. + { + bucketName: bucketName, + uploadID: uploadID, + copySourceHeader: url.QueryEscape("/" + bucketName + "/" + objectName), + maximumPartNumber: true, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + expectedRespStatus: http.StatusOK, + }, + } + + for i, testCase := range testCases { + var req *http.Request + var reqV2 *http.Request + // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. + rec := httptest.NewRecorder() + if !testCase.invalidPartNumber || !testCase.maximumPartNumber { + // construct HTTP request for copy object. + req, err = newTestSignedRequestV4("PUT", getCopyObjectPartURL("", testCase.bucketName, testObject, testCase.uploadID, "1"), 0, nil, testCase.accessKey, testCase.secretKey) + } else if testCase.invalidPartNumber { + req, err = newTestSignedRequestV4("PUT", getCopyObjectPartURL("", testCase.bucketName, testObject, testCase.uploadID, "abc"), 0, nil, testCase.accessKey, testCase.secretKey) + } else if testCase.maximumPartNumber { + req, err = newTestSignedRequestV4("PUT", getCopyObjectPartURL("", testCase.bucketName, testObject, testCase.uploadID, "99999"), 0, nil, testCase.accessKey, testCase.secretKey) + } + if err != nil { + t.Fatalf("Test %d: Failed to create HTTP request for copy Object: %v", i+1, err) + } + + // "X-Amz-Copy-Source" header contains the information about the source bucket and the object to copied. + if testCase.copySourceHeader != "" { + req.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader) + } + if testCase.copySourceRange != "" { + req.Header.Set("X-Amz-Copy-Source-Range", testCase.copySourceRange) + } + // Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler. + // Call the ServeHTTP to execute the handler, `func (api objectAPIHandlers) CopyObjectHandler` handles the request. + apiRouter.ServeHTTP(rec, req) + // Assert the response code with the expected status. + if rec.Code != testCase.expectedRespStatus { + t.Fatalf("Test %d: %s: Expected the response status to be `%d`, but instead found `%d`", i+1, instanceType, testCase.expectedRespStatus, rec.Code) + } + if rec.Code == http.StatusOK { + // See if the new part has been uploaded. + // testing whether the copy was successful. + var results ListPartsInfo + results, err = obj.ListObjectParts(testCase.bucketName, testObject, testCase.uploadID, 0, 1) + if err != nil { + t.Fatalf("Test %d: %s: Failed to look for copied object part: %s", i+1, instanceType, err) + } + if len(results.Parts) != 1 { + t.Fatalf("Test %d: %s: Expected only one entry returned %d entries", i+1, instanceType, len(results.Parts)) + } + } + + // Verify response of the V2 signed HTTP request. + // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. + recV2 := httptest.NewRecorder() + + reqV2, err = newTestRequest("PUT", getCopyObjectPartURL("", testCase.bucketName, testObject, testCase.uploadID, "1"), 0, nil) + if err != nil { + t.Fatalf("Test %d: Failed to create HTTP request for copy Object: %v", i+1, err) + } + // "X-Amz-Copy-Source" header contains the information about the source bucket and the object to copied. + if testCase.copySourceHeader != "" { + reqV2.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader) + } + if testCase.copySourceRange != "" { + reqV2.Header.Set("X-Amz-Copy-Source-Range", testCase.copySourceRange) + } + + err = signRequestV2(reqV2, testCase.accessKey, testCase.secretKey) + if err != nil { + t.Fatalf("Failed to V2 Sign the HTTP request: %v.", err) + } + + // Since `apiRouter` satisfies `http.Handler` it has a ServeHTTP to execute the logic of the handler. + // Call the ServeHTTP to execute the handler. + apiRouter.ServeHTTP(recV2, reqV2) + if recV2.Code != testCase.expectedRespStatus { + t.Errorf("Test %d: %s: Expected the response status to be `%d`, but instead found `%d`", i+1, instanceType, testCase.expectedRespStatus, recV2.Code) + } + } + + // HTTP request for testing when `ObjectLayer` is set to `nil`. + // There is no need to use an existing bucket and valid input for creating the request + // since the `objectLayer==nil` check is performed before any other checks inside the handlers. + // The only aim is to generate an HTTP request in a way that the relevant/registered end point is evoked/called. + nilBucket := "dummy-bucket" + nilObject := "dummy-object" + + nilReq, err := newTestSignedRequestV4("PUT", getCopyObjectPartURL("", nilBucket, nilObject, "0", "0"), + 0, bytes.NewReader([]byte("testNilObjLayer")), "", "") + if err != nil { + t.Errorf("Minio %s: Failed to create http request for testing the response when object Layer is set to `nil`.", instanceType) + } + + // Below is how CopyObjectPartHandler is registered. + // bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(api.CopyObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") + // Its necessary to set the "X-Amz-Copy-Source" header for the request to be accepted by the handler. + nilReq.Header.Set("X-Amz-Copy-Source", url.QueryEscape("/"+nilBucket+"/"+nilObject)) + + // execute the object layer set to `nil` test. + // `ExecObjectLayerAPINilTest` manages the operation. + ExecObjectLayerAPINilTest(t, nilBucket, nilObject, instanceType, apiRouter, nilReq) + +} + // Wrapper for calling Copy Object API handler tests for both XL multiple disks and single node setup. func TestAPICopyObjectHandler(t *testing.T) { defer DetectTestLeak(t)() diff --git a/cmd/object_api_suite_test.go b/cmd/object_api_suite_test.go index 88ad87964..e3cb467ad 100644 --- a/cmd/object_api_suite_test.go +++ b/cmd/object_api_suite_test.go @@ -106,15 +106,18 @@ func testMultipartObjectCreation(obj ObjectLayer, instanceType string, c TestErr for i := 1; i <= 10; i++ { expectedMD5Sumhex := getMD5Hash(data) - var calculatedMD5sum string - calculatedMD5sum, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(data)), bytes.NewBuffer(data), expectedMD5Sumhex, "") + var calcPartInfo PartInfo + calcPartInfo, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(data)), bytes.NewBuffer(data), expectedMD5Sumhex, "") if err != nil { c.Errorf("%s: %s", instanceType, err) } - if calculatedMD5sum != expectedMD5Sumhex { + if calcPartInfo.ETag != expectedMD5Sumhex { c.Errorf("MD5 Mismatch") } - completedParts.Parts = append(completedParts.Parts, completePart{PartNumber: i, ETag: calculatedMD5sum}) + completedParts.Parts = append(completedParts.Parts, completePart{ + PartNumber: i, + ETag: calcPartInfo.ETag, + }) } objInfo, err := obj.CompleteMultipartUpload("bucket", "key", uploadID, completedParts.Parts) if err != nil { @@ -153,12 +156,12 @@ func testMultipartObjectAbort(obj ObjectLayer, instanceType string, c TestErrHan expectedMD5Sumhex := getMD5Hash([]byte(randomString)) metadata["md5"] = expectedMD5Sumhex - var calculatedMD5sum string - calculatedMD5sum, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(randomString)), bytes.NewBufferString(randomString), expectedMD5Sumhex, "") + var calcPartInfo PartInfo + calcPartInfo, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(randomString)), bytes.NewBufferString(randomString), expectedMD5Sumhex, "") if err != nil { c.Fatalf("%s: %s", instanceType, err) } - if calculatedMD5sum != expectedMD5Sumhex { + if calcPartInfo.ETag != expectedMD5Sumhex { c.Errorf("Md5 Mismatch") } parts[i] = expectedMD5Sumhex diff --git a/cmd/posix-list-dir-nix.go b/cmd/posix-list-dir-nix.go index 62421abce..4e2025b86 100644 --- a/cmd/posix-list-dir-nix.go +++ b/cmd/posix-list-dir-nix.go @@ -1,4 +1,4 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd +// +build linux darwin freebsd netbsd openbsd /* * Minio Cloud Storage, (C) 2016 Minio, Inc. @@ -68,10 +68,6 @@ func parseDirents(dirPath string, buf []byte) (entries []string, err error) { if name == "." || name == ".." { continue } - // Skip special files. - if hasPosixReservedPrefix(name) { - continue - } switch dirent.Type { case syscall.DT_DIR: diff --git a/cmd/posix-list-dir-others.go b/cmd/posix-list-dir-others.go index abd3d965b..3cc2ec246 100644 --- a/cmd/posix-list-dir-others.go +++ b/cmd/posix-list-dir-others.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin,!openbsd,!freebsd,!netbsd,!dragonfly +// +build !linux,!darwin,!openbsd,!freebsd,!netbsd /* * Minio Cloud Storage, (C) 2016 Minio, Inc. @@ -52,10 +52,6 @@ func readDir(dirPath string) (entries []string, err error) { return nil, err } for _, fi := range fis { - // Skip special files, if found. - if hasPosixReservedPrefix(fi.Name()) { - continue - } // Stat symbolic link and follow to get the final value. if fi.Mode()&os.ModeSymlink == os.ModeSymlink { var st os.FileInfo diff --git a/cmd/posix-list-dir_test.go b/cmd/posix-list-dir_test.go index c709f7ec5..30d85b862 100644 --- a/cmd/posix-list-dir_test.go +++ b/cmd/posix-list-dir_test.go @@ -69,26 +69,6 @@ func setupTestReadDirEmpty(t *testing.T) (testResults []result) { return testResults } -// Test to read empty directory with only reserved names. -func setupTestReadDirReserved(t *testing.T) (testResults []result) { - dir := mustSetupDir(t) - entries := []string{} - // Create a file with reserved name. - for _, reservedName := range posixReservedPrefix { - if err := ioutil.WriteFile(filepath.Join(dir, reservedName), []byte{}, os.ModePerm); err != nil { - // For cleanup, its required to add these entries into test results. - testResults = append(testResults, result{dir, entries}) - t.Fatalf("Unable to create file, %s", err) - } - // entries = append(entries, reservedName) - reserved files are skipped. - } - sort.Strings(entries) - - // Add entries slice for this test directory. - testResults = append(testResults, result{dir, entries}) - return testResults -} - // Test to read non-empty directory with only files. func setupTestReadDirFiles(t *testing.T) (testResults []result) { dir := mustSetupDir(t) @@ -198,8 +178,6 @@ func TestReadDir(t *testing.T) { // Setup and capture test results for empty directory. testResults = append(testResults, setupTestReadDirEmpty(t)...) - // Setup and capture test results for reserved files. - testResults = append(testResults, setupTestReadDirReserved(t)...) // Setup and capture test results for directory with only files. testResults = append(testResults, setupTestReadDirFiles(t)...) // Setup and capture test results for directory with files and directories. diff --git a/cmd/posix-utils_nix.go b/cmd/posix-utils_nix.go index ebb59ad61..9b4fa5952 100644 --- a/cmd/posix-utils_nix.go +++ b/cmd/posix-utils_nix.go @@ -1,7 +1,7 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd +// +build linux darwin dragonfly freebsd netbsd openbsd solaris /* - * Minio Cloud Storage, (C) 2016 Minio, Inc. + * Minio Cloud Storage, (C) 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cmd/posix.go b/cmd/posix.go index 0a1969fda..89d1c77ed 100644 --- a/cmd/posix.go +++ b/cmd/posix.go @@ -153,11 +153,20 @@ func getDiskInfo(diskPath string) (di disk.Info, err error) { return di, err } +// List of operating systems where we ignore disk space +// verification. +var ignoreDiskFreeOS = []string{ + globalWindowsOSName, + globalNetBSDOSName, + globalSolarisOSName, +} + // checkDiskFree verifies if disk path has sufficient minimum free disk space and files. func (s *posix) checkDiskFree() (err error) { // We don't validate disk space or inode utilization on windows. // Each windows calls to 'GetVolumeInformationW' takes around 3-5seconds. - if runtime.GOOS == globalWindowsOSName { + // And StatFS is not supported by Go for solaris and netbsd. + if contains(ignoreDiskFreeOS, runtime.GOOS) { return nil } diff --git a/cmd/post-policy_test.go b/cmd/post-policy_test.go index 60333e3a3..14018979a 100644 --- a/cmd/post-policy_test.go +++ b/cmd/post-policy_test.go @@ -342,46 +342,66 @@ func testPostPolicyBucketHandler(obj ObjectLayer, instanceType string, t TestErr } testCases2 := []struct { - objectName string - data []byte - expectedRespStatus int - accessKey string - secretKey string - malformedBody bool + objectName string + data []byte + expectedRespStatus int + accessKey string + secretKey string + malformedBody bool + ignoreContentLength bool }{ // Success case. { - objectName: "test", - data: bytes.Repeat([]byte("a"), 1025), - expectedRespStatus: http.StatusNoContent, - accessKey: credentials.AccessKey, - secretKey: credentials.SecretKey, - malformedBody: false, + objectName: "test", + data: bytes.Repeat([]byte("a"), 1025), + expectedRespStatus: http.StatusNoContent, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + malformedBody: false, + ignoreContentLength: false, + }, + // Failed with Content-Length not specified. + { + objectName: "test", + data: bytes.Repeat([]byte("a"), 1025), + expectedRespStatus: http.StatusNoContent, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + malformedBody: false, + ignoreContentLength: true, }, // Failed with entity too small. { - objectName: "test", - data: bytes.Repeat([]byte("a"), 1023), - expectedRespStatus: http.StatusBadRequest, - accessKey: credentials.AccessKey, - secretKey: credentials.SecretKey, - malformedBody: false, + objectName: "test", + data: bytes.Repeat([]byte("a"), 1023), + expectedRespStatus: http.StatusBadRequest, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + malformedBody: false, + ignoreContentLength: false, }, // Failed with entity too large. { - objectName: "test", - data: bytes.Repeat([]byte("a"), (1*humanize.MiByte)+1), - expectedRespStatus: http.StatusBadRequest, - accessKey: credentials.AccessKey, - secretKey: credentials.SecretKey, - malformedBody: false, + objectName: "test", + data: bytes.Repeat([]byte("a"), (1*humanize.MiByte)+1), + expectedRespStatus: http.StatusBadRequest, + accessKey: credentials.AccessKey, + secretKey: credentials.SecretKey, + malformedBody: false, + ignoreContentLength: false, }, } for i, testCase := range testCases2 { // initialize HTTP NewRecorder, this records any mutations to response writer inside the handler. rec := httptest.NewRecorder() - req, perr := newPostRequestV4WithContentLength("", bucketName, testCase.objectName, testCase.data, testCase.accessKey, testCase.secretKey) + var req *http.Request + var perr error + if testCase.ignoreContentLength { + req, perr = newPostRequestV4("", bucketName, testCase.objectName, testCase.data, testCase.accessKey, testCase.secretKey) + } else { + req, perr = newPostRequestV4WithContentLength("", bucketName, testCase.objectName, testCase.data, testCase.accessKey, testCase.secretKey) + } if perr != nil { t.Fatalf("Test %d: %s: Failed to create HTTP request for PostPolicyHandler: %v", i+1, instanceType, perr) } diff --git a/cmd/prepare-storage.go b/cmd/prepare-storage.go index 36bb20a1e..839474484 100644 --- a/cmd/prepare-storage.go +++ b/cmd/prepare-storage.go @@ -198,10 +198,11 @@ func retryFormattingXLDisks(firstDisk bool, endpoints []*url.URL, storageDisks [ return errInvalidArgument } - // Create a done channel to control 'ListObjects' go routine. - doneCh := make(chan struct{}, 1) + // Done channel is used to close any lingering retry routine, as soon + // as this function returns. + doneCh := make(chan struct{}) - // Indicate to our routine to exit cleanly upon return. + // Indicate to our retry routine to exit cleanly, upon this function return. defer close(doneCh) // prepare getElapsedTime() to calculate elapsed time since we started trying formatting disks. @@ -212,7 +213,7 @@ func retryFormattingXLDisks(firstDisk bool, endpoints []*url.URL, storageDisks [ } // Wait on the jitter retry loop. - retryTimerCh := newRetryTimer(time.Second, time.Second*30, MaxJitter, doneCh) + retryTimerCh := newRetryTimerSimple(doneCh) for { select { case retryCount := <-retryTimerCh: diff --git a/cmd/retry-storage.go b/cmd/retry-storage.go index 23a7526a3..f30170ed8 100644 --- a/cmd/retry-storage.go +++ b/cmd/retry-storage.go @@ -220,9 +220,12 @@ func (f retryStorage) reInit() (err error) { // Close the underlying connection. f.remoteStorage.Close() // Error here is purposefully ignored. + // Done channel is used to close any lingering retry routine, as soon + // as this function returns. doneCh := make(chan struct{}) defer close(doneCh) - for i := range newRetryTimer(f.retryUnit, f.retryCap, MaxJitter, doneCh) { + + for i := range newRetryTimer(f.retryUnit, f.retryCap, doneCh) { // Initialize and make a new login attempt. err = f.remoteStorage.Init() if err != nil { diff --git a/cmd/retry.go b/cmd/retry.go index d3ad59e20..5e42182c6 100644 --- a/cmd/retry.go +++ b/cmd/retry.go @@ -48,7 +48,8 @@ func (r *lockedRandSource) Seed(seed int64) { // MaxJitter will randomize over the full exponential backoff time const MaxJitter = 1.0 -// NoJitter disables the use of jitter for randomizing the exponential backoff time +// NoJitter disables the use of jitter for randomizing the +// exponential backoff time const NoJitter = 0.0 // Global random source for fetching random values. @@ -56,9 +57,11 @@ var globalRandomSource = rand.New(&lockedRandSource{ src: rand.NewSource(time.Now().UTC().UnixNano()), }) -// newRetryTimer creates a timer with exponentially increasing delays -// until the maximum retry attempts are reached. -func newRetryTimer(unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int { +// newRetryTimerJitter creates a timer with exponentially increasing delays +// until the maximum retry attempts are reached. - this function is a fully +// configurable version, meant for only advanced use cases. For the most part +// one should use newRetryTimerSimple and newRetryTimer. +func newRetryTimerWithJitter(unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int { attemptCh := make(chan int) // normalize jitter to the range [0, 1.0] @@ -91,17 +94,49 @@ func newRetryTimer(unit time.Duration, cap time.Duration, jitter float64, doneCh go func() { defer close(attemptCh) nextBackoff := 0 + // Channel used to signal after the expiry of backoff wait seconds. + var timer *time.Timer for { - select { - // Attempts starts. + select { // Attempts starts. case attemptCh <- nextBackoff: nextBackoff++ case <-doneCh: // Stop the routine. return } - time.Sleep(exponentialBackoffWait(nextBackoff)) + timer = time.NewTimer(exponentialBackoffWait(nextBackoff)) + // wait till next backoff time or till doneCh gets a message. + select { + case <-timer.C: + case <-doneCh: + // stop the timer and return. + timer.Stop() + return + } + } }() + + // Start reading.. return attemptCh } + +// Default retry constants. +var ( + defaultRetryUnit = time.Second // 1 second. + defaultRetryCap = 30 * time.Second // 30 seconds. +) + +// newRetryTimer creates a timer with exponentially increasing delays +// until the maximum retry attempts are reached. - this function provides +// resulting retry values to be of maximum jitter. +func newRetryTimer(unit time.Duration, cap time.Duration, doneCh chan struct{}) <-chan int { + return newRetryTimerWithJitter(unit, cap, MaxJitter, doneCh) +} + +// newRetryTimerSimple creates a timer with exponentially increasing delays +// until the maximum retry attempts are reached. - this function is a +// simpler version with all default values. +func newRetryTimerSimple(doneCh chan struct{}) <-chan int { + return newRetryTimerWithJitter(defaultRetryUnit, defaultRetryCap, MaxJitter, doneCh) +} diff --git a/cmd/retry_test.go b/cmd/retry_test.go new file mode 100644 index 000000000..0b9614001 --- /dev/null +++ b/cmd/retry_test.go @@ -0,0 +1,82 @@ +/* + * Minio Cloud Storage, (C) 2016 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmd + +import ( + "testing" + "time" +) + +// Tests for retry timer. +func TestRetryTimerSimple(t *testing.T) { + doneCh := make(chan struct{}) + attemptCh := newRetryTimerSimple(doneCh) + i := <-attemptCh + if i != 0 { + close(doneCh) + t.Fatalf("Invalid attempt counter returned should be 0, found %d instead", i) + } + i = <-attemptCh + if i <= 0 { + close(doneCh) + t.Fatalf("Invalid attempt counter returned should be greater than 0, found %d instead", i) + } + close(doneCh) + _, ok := <-attemptCh + if ok { + t.Fatal("Attempt counter should be closed") + } +} + +// Test retry time with no jitter. +func TestRetryTimerWithNoJitter(t *testing.T) { + doneCh := make(chan struct{}) + // No jitter + attemptCh := newRetryTimerWithJitter(time.Millisecond, 5*time.Millisecond, NoJitter, doneCh) + i := <-attemptCh + if i != 0 { + close(doneCh) + t.Fatalf("Invalid attempt counter returned should be 0, found %d instead", i) + } + // Loop through the maximum possible attempt. + for i = range attemptCh { + if i == 30 { + close(doneCh) + } + } + _, ok := <-attemptCh + if ok { + t.Fatal("Attempt counter should be closed") + } +} + +// Test retry time with Jitter greater than MaxJitter. +func TestRetryTimerWithJitter(t *testing.T) { + doneCh := make(chan struct{}) + // Jitter will be set back to 1.0 + attemptCh := newRetryTimerWithJitter(defaultRetryUnit, defaultRetryCap, 2.0, doneCh) + i := <-attemptCh + if i != 0 { + close(doneCh) + t.Fatalf("Invalid attempt counter returned should be 0, found %d instead", i) + } + close(doneCh) + _, ok := <-attemptCh + if ok { + t.Fatal("Attempt counter should be closed") + } +} diff --git a/cmd/routers.go b/cmd/routers.go index dfee5e590..9213f65be 100644 --- a/cmd/routers.go +++ b/cmd/routers.go @@ -84,6 +84,8 @@ func configureServerHandler(srvCmdConfig serverCmdConfig) (http.Handler, error) // List of some generic handlers which are applied for all incoming requests. var handlerFns = []HandlerFunc{ + // Network statistics + setHTTPStatsHandler, // Limits all requests size to a maximum fixed limit setRequestSizeLimitHandler, // Adds 'crossdomain.xml' policy handler to serve legacy flash clients. diff --git a/cmd/runtime-checks.go b/cmd/runtime-checks.go deleted file mode 100644 index fc16e53e7..000000000 --- a/cmd/runtime-checks.go +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2015, 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cmd - -import ( - "fmt" - "runtime" - - "github.com/hashicorp/go-version" - "github.com/minio/mc/pkg/console" -) - -// check if minimum Go version is met. -func checkGoVersion() { - // Current version. - curVersion, e := version.NewVersion(runtime.Version()[2:]) - if e != nil { - console.Fatalln("Unable to determine current go version.", e) - } - - // Prepare version constraint. - constraints, e := version.NewConstraint(minGoVersion) - if e != nil { - console.Fatalln("Unable to check go version.") - } - - // Check for minimum version. - if !constraints.Check(curVersion) { - console.Fatalln(fmt.Sprintf("Please recompile Minio with Golang version %s.", minGoVersion)) - } -} diff --git a/cmd/server-main.go b/cmd/server-main.go index 431d25a14..f48f90d07 100644 --- a/cmd/server-main.go +++ b/cmd/server-main.go @@ -21,11 +21,11 @@ import ( "fmt" "net" "net/url" - "os" "path" "sort" "strconv" "strings" + "time" "runtime" @@ -52,7 +52,7 @@ USAGE: minio {{.Name}} [FLAGS] PATH [PATH...] FLAGS: - {{range .Flags}}{{.}} + {{range .VisibleFlags}}{{.}} {{end}} ENVIRONMENT VARIABLES: ACCESS: @@ -128,22 +128,17 @@ func parseStorageEndpoints(eps []string) (endpoints []*url.URL, err error) { return endpoints, nil } -// initServerConfig initialize server config. +// initServer initialize server config. func initServerConfig(c *cli.Context) { + // Initialization such as config generating/loading config, enable logging, .. + minioInit(c) + // Create certs path. - err := createCertsPath() - fatalIf(err, "Unable to create \"certs\" directory.") + fatalIf(createCertsPath(), "Unable to create \"certs\" directory.") // Load user supplied root CAs loadRootCAs() - // When credentials inherited from the env, server cmd has to save them in the disk - if os.Getenv("MINIO_ACCESS_KEY") != "" && os.Getenv("MINIO_SECRET_KEY") != "" { - // Env credentials are already loaded in serverConfig, just save in the disk - err = serverConfig.Save() - fatalIf(err, "Unable to save credentials in the disk.") - } - // Set maxOpenFiles, This is necessary since default operating // system limits of 1024, 2048 are not enough for Minio server. setMaxOpenFiles() @@ -352,9 +347,14 @@ func getHostPort(address string) (host, port string, err error) { return "", "", err } - // Check if port is available. - if err = checkPortAvailability(port); err != nil { - return "", "", err + if runtime.GOOS == "darwin" { + // On macOS, if a process already listens on 127.0.0.1:PORT, net.Listen() falls back + // to IPv6 address ie minio will start listening on IPv6 address whereas another + // (non-)minio process is listening on IPv4 of given port. + // To avoid this error sutiation we check for port availability only for macOS. + if err = checkPortAvailability(port); err != nil { + return "", "", err + } } // Success. @@ -367,8 +367,8 @@ func serverMain(c *cli.Context) { cli.ShowCommandHelpAndExit(c, "server", 1) } - // Initialization routine, such as config loading, enable logging, .. - minioInit(c) + // Initializes server config, certs, logging and system settings. + initServerConfig(c) // Check for new updates from dl.minio.io. checkUpdate() @@ -385,9 +385,6 @@ func serverMain(c *cli.Context) { // as parseStorageEndpoints() depends on it. checkServerSyntax(c) - // Initialize server config. - initServerConfig(c) - // Disks to be used in server init. endpoints, err := parseStorageEndpoints(c.Args()) fatalIf(err, "Unable to parse storage endpoints %s", c.Args()) @@ -444,8 +441,8 @@ func serverMain(c *cli.Context) { initGlobalAdminPeers(endpoints) // Determine API endpoints where we are going to serve the S3 API from. - apiEndPoints, err := finalizeAPIEndpoints(apiServer.Server) - fatalIf(err, "Unable to finalize API endpoints for %s", apiServer.Server.Addr) + apiEndPoints, err := finalizeAPIEndpoints(apiServer.Addr) + fatalIf(err, "Unable to finalize API endpoints for %s", apiServer.Addr) // Set the global API endpoints value. globalAPIEndpoints = apiEndPoints @@ -472,6 +469,9 @@ func serverMain(c *cli.Context) { // Prints the formatted startup message once object layer is initialized. printStartupMessage(apiEndPoints) + // Set uptime time after object layer has initialized. + globalBootTime = time.Now().UTC() + // Waits on the server. <-globalServiceDoneCh } diff --git a/cmd/server-main_test.go b/cmd/server-main_test.go index df152b3ae..84416bb62 100644 --- a/cmd/server-main_test.go +++ b/cmd/server-main_test.go @@ -19,7 +19,6 @@ package cmd import ( "errors" "flag" - "net/http" "os" "reflect" "runtime" @@ -34,7 +33,7 @@ func TestGetListenIPs(t *testing.T) { port string shouldPass bool }{ - {"localhost", "9000", true}, + {"127.0.0.1", "9000", true}, {"", "9000", true}, {"", "", false}, } @@ -115,14 +114,12 @@ func TestFinalizeAPIEndpoints(t *testing.T) { }{ {":80"}, {":80"}, - {"localhost:80"}, - {"localhost:80"}, + {"127.0.0.1:80"}, + {"127.0.0.1:80"}, } for i, test := range testCases { - endPoints, err := finalizeAPIEndpoints(&http.Server{ - Addr: test.addr, - }) + endPoints, err := finalizeAPIEndpoints(test.addr) if err != nil && len(endPoints) <= 0 { t.Errorf("Test case %d returned with no API end points for %s", i+1, test.addr) @@ -286,18 +283,18 @@ func TestParseStorageEndpoints(t *testing.T) { host string expectedErr error }{ - {"", "http://localhost/export", nil}, + {"", "http://127.0.0.1/export", nil}, { "testhost", - "http://localhost/export", - errors.New("Invalid Argument localhost, port mandatory when --address : is used"), + "http://127.0.0.1/export", + errors.New("Invalid Argument 127.0.0.1, port mandatory when --address : is used"), }, { "", - "http://localhost:9000/export", - errors.New("Invalid Argument localhost:9000, port configurable using --address :"), + "http://127.0.0.1:9000/export", + errors.New("Invalid Argument 127.0.0.1:9000, port configurable using --address :"), }, - {"testhost", "http://localhost:9000/export", nil}, + {"testhost", "http://127.0.0.1:9000/export", nil}, } for i, test := range testCases { globalMinioHost = test.globalMinioHost @@ -318,15 +315,15 @@ func TestCheckEndpointsSyntax(t *testing.T) { successCases := []string{ "export", "/export", - "http://localhost/export", - "https://localhost/export", + "http://127.0.0.1/export", + "https://127.0.0.1/export", } failureCases := []string{ "/", - "http://localhost", - "http://localhost/", - "ftp://localhost/export", + "http://127.0.0.1", + "http://127.0.0.1/", + "ftp://127.0.0.1/export", "server:/export", } @@ -455,8 +452,14 @@ func TestIsDistributedSetup(t *testing.T) { globalMinioHost = "" } -func TestInitServerConfig(t *testing.T) { - ctx := &cli.Context{} +// Tests init server. +func TestInitServer(t *testing.T) { + app := cli.NewApp() + app.Commands = []cli.Command{serverCmd} + serverFlagSet := flag.NewFlagSet("server", 0) + serverFlagSet.String("address", ":9000", "") + ctx := cli.NewContext(app, serverFlagSet, serverFlagSet) + root, err := newTestConfig(globalMinioDefaultRegion) if err != nil { t.Fatal("Failed to set up test config") @@ -476,6 +479,7 @@ func TestInitServerConfig(t *testing.T) { t.Fatalf("Test %d failed with %v", i+1, tErr) } initServerConfig(ctx) + os.Unsetenv(test.envVar) } } @@ -491,8 +495,8 @@ func TestIsAnyEndpointLocal(t *testing.T) { result: false, }, { - disks: []string{"http://localhost/mnt/disk1", - "http://localhost/mnt/disk1"}, + disks: []string{"http://127.0.0.1/mnt/disk1", + "http://127.0.0.1/mnt/disk1"}, result: true, }, } diff --git a/cmd/server-mux.go b/cmd/server-mux.go index 16d525d28..8ea33a3d5 100644 --- a/cmd/server-mux.go +++ b/cmd/server-mux.go @@ -58,16 +58,16 @@ var defaultHTTP1Methods = []string{ // connections on the same listeners. type ConnMux struct { net.Conn - bufrw *bufio.ReadWriter + // To peek net.Conn incoming data + peeker *bufio.Reader } // NewConnMux - creates a new ConnMux instance func NewConnMux(c net.Conn) *ConnMux { br := bufio.NewReader(c) - bw := bufio.NewWriter(c) return &ConnMux{ - Conn: c, - bufrw: bufio.NewReadWriter(br, bw), + Conn: c, + peeker: bufio.NewReader(br), } } @@ -83,7 +83,7 @@ const ( // errors in peeking over the connection. func (c *ConnMux) PeekProtocol() (string, error) { // Peek for HTTP verbs. - buf, err := c.bufrw.Peek(maxHTTPVerbLen) + buf, err := c.peeker.Peek(maxHTTPVerbLen) if err != nil { return "", err } @@ -110,20 +110,31 @@ func (c *ConnMux) PeekProtocol() (string, error) { // Read - streams the ConnMux buffer when reset flag is activated, otherwise // streams from the incoming network connection -func (c *ConnMux) Read(b []byte) (int, error) { +func (c *ConnMux) Read(b []byte) (n int, e error) { // Push read deadline c.Conn.SetReadDeadline(time.Now().Add(defaultTCPReadTimeout)) - return c.bufrw.Read(b) + + // Update server's connection statistics + defer func() { + globalConnStats.incInputBytes(n) + }() + + return c.peeker.Read(b) +} + +func (c *ConnMux) Write(b []byte) (n int, e error) { + // Update server's connection statistics + defer func() { + globalConnStats.incOutputBytes(n) + }() + // Run the underlying net.Conn Write() func + return c.Conn.Write(b) } // Close the connection. func (c *ConnMux) Close() (err error) { // Make sure that we always close a connection, - // even if the bufioWriter flush sends an error. - defer c.Conn.Close() - - // Flush and write to the connection. - return c.bufrw.Flush() + return c.Conn.Close() } // ListenerMux wraps the standard net.Listener to inspect @@ -309,32 +320,28 @@ func (l *ListenerMux) Accept() (net.Conn, error) { // ServerMux - the main mux server type ServerMux struct { - *http.Server - listeners []*ListenerMux - WaitGroup *sync.WaitGroup - GracefulTimeout time.Duration - mu sync.Mutex // guards closed, conns, and listener - closed bool - conns map[net.Conn]http.ConnState // except terminal states + Addr string + handler http.Handler + listeners []*ListenerMux + + gracefulWait *sync.WaitGroup + gracefulTimeout time.Duration + + mu sync.Mutex // guards closed, and listener + closed bool } // NewServerMux constructor to create a ServerMux func NewServerMux(addr string, handler http.Handler) *ServerMux { m := &ServerMux{ - Server: &http.Server{ - Addr: addr, - Handler: handler, - MaxHeaderBytes: 1 << 20, - }, - WaitGroup: &sync.WaitGroup{}, + Addr: addr, + handler: handler, // Wait for 5 seconds for new incoming connnections, otherwise // forcibly close them during graceful stop or restart. - GracefulTimeout: 5 * time.Second, + gracefulTimeout: 5 * time.Second, + gracefulWait: &sync.WaitGroup{}, } - // Track connection state - m.connState() - // Returns configured HTTP server. return m } @@ -421,7 +428,7 @@ func (m *ServerMux) ListenAndServe(certFile, keyFile string) (err error) { go m.handleServiceSignals() - listeners, err := initListeners(m.Server.Addr, config) + listeners, err := initListeners(m.Addr, config) if err != nil { return err } @@ -445,8 +452,11 @@ func (m *ServerMux) ListenAndServe(certFile, keyFile string) (err error) { } http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect) } else { - // Execute registered handlers - m.Server.Handler.ServeHTTP(w, r) + // Execute registered handlers, protect with a waitgroup + // to accomplish a graceful shutdown when the user asks to quit + m.gracefulWait.Add(1) + m.handler.ServeHTTP(w, r) + m.gracefulWait.Done() } }) @@ -470,6 +480,7 @@ func (m *ServerMux) ListenAndServe(certFile, keyFile string) (err error) { // Close initiates the graceful shutdown func (m *ServerMux) Close() error { m.mu.Lock() + if m.closed { m.mu.Unlock() return errors.New("Server has been closed") @@ -484,76 +495,21 @@ func (m *ServerMux) Close() error { return err } } - - m.SetKeepAlivesEnabled(false) - // Force close any idle and new connections. Waiting for other connections - // to close on their own (within the timeout period) - for c, st := range m.conns { - if st == http.StateIdle || st == http.StateNew { - c.Close() - } - } - - // If the GracefulTimeout happens then forcefully close all connections - t := time.AfterFunc(m.GracefulTimeout, func() { - for c := range m.conns { - c.Close() - } - }) - - // Wait for graceful timeout of connections. - defer t.Stop() - m.mu.Unlock() - // Block until all connections are closed - m.WaitGroup.Wait() + // Prepare for a graceful shutdown + waitSignal := make(chan struct{}) + go func() { + defer close(waitSignal) + m.gracefulWait.Wait() + }() + + select { + // Wait for everything to be properly closed + case <-waitSignal: + // Forced shutdown + case <-time.After(m.gracefulTimeout): + } return nil } - -// connState setups the ConnState tracking hook to know which connections are idle -func (m *ServerMux) connState() { - // Set our ConnState to track idle connections - m.Server.ConnState = func(c net.Conn, cs http.ConnState) { - m.mu.Lock() - defer m.mu.Unlock() - - switch cs { - case http.StateNew: - // New connections increment the WaitGroup and are added the the conns dictionary - m.WaitGroup.Add(1) - if m.conns == nil { - m.conns = make(map[net.Conn]http.ConnState) - } - m.conns[c] = cs - case http.StateActive: - // Only update status to StateActive if it's in the conns dictionary - if _, ok := m.conns[c]; ok { - m.conns[c] = cs - } - case http.StateIdle: - // Only update status to StateIdle if it's in the conns dictionary - if _, ok := m.conns[c]; ok { - m.conns[c] = cs - } - - // If we've already closed then we need to close this connection. - // We don't allow connections to become idle after server is closed - if m.closed { - c.Close() - } - case http.StateHijacked, http.StateClosed: - // If the connection is hijacked or closed we forget it - m.forgetConn(c) - } - } -} - -// forgetConn removes c from conns and decrements WaitGroup -func (m *ServerMux) forgetConn(c net.Conn) { - if _, ok := m.conns[c]; ok { - delete(m.conns, c) - m.WaitGroup.Done() - } -} diff --git a/cmd/server-mux_test.go b/cmd/server-mux_test.go index 661ad05a4..1a24473a6 100644 --- a/cmd/server-mux_test.go +++ b/cmd/server-mux_test.go @@ -29,7 +29,6 @@ import ( "math/big" "net" "net/http" - "net/http/httptest" "os" "runtime" "sync" @@ -181,113 +180,111 @@ func TestClose(t *testing.T) { } func TestServerMux(t *testing.T) { - ts := httptest.NewUnstartedServer(nil) - defer ts.Close() + var err error + var got []byte + var res *http.Response // Create ServerMux - m := NewServerMux("", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + m := NewServerMux("127.0.0.1:0", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") })) + // Start serving requests + go m.ListenAndServe("", "") - // Set the test server config to the mux - ts.Config = m.Server - ts.Start() - - // Create a ListenerMux - lm := &ListenerMux{ - Listener: ts.Listener, - config: &tls.Config{}, - cond: sync.NewCond(&sync.Mutex{}), + // Issue a GET request. Since we started server in a goroutine, it could be not ready + // at this point. So we allow until 5 failed retries before declare there is an error + for i := 0; i < 5; i++ { + // Sleep one second + time.Sleep(1 * time.Second) + // Check if one listener is ready + m.mu.Lock() + if len(m.listeners) == 0 { + m.mu.Unlock() + continue + } + m.mu.Unlock() + // Issue the GET request + client := http.Client{} + m.mu.Lock() + res, err = client.Get("http://" + m.listeners[0].Addr().String()) + m.mu.Unlock() + if err != nil { + continue + } + // Read the request response + got, err = ioutil.ReadAll(res.Body) } - m.listeners = []*ListenerMux{lm} - client := http.Client{} - res, err := client.Get(ts.URL) - if err != nil { - t.Fatal(err) - } - - got, err := ioutil.ReadAll(res.Body) + // Check for error persisted after 5 times if err != nil { t.Fatal(err) } + // Check the web service response if string(got) != "hello" { t.Errorf("got %q, want hello", string(got)) } - - // Make sure there is only 1 connection - m.mu.Lock() - if len(m.conns) < 1 { - t.Fatal("Should have 1 connections") - } - m.mu.Unlock() - - // Close the server - m.Close() - - // Make sure there are zero connections - m.mu.Lock() - if len(m.conns) > 0 { - t.Fatal("Should have 0 connections") - } - m.mu.Unlock() } func TestServerCloseBlocking(t *testing.T) { - ts := httptest.NewUnstartedServer(nil) - defer ts.Close() - // Create ServerMux - m := NewServerMux("", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + m := NewServerMux("127.0.0.1:0", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello") })) - // Set the test server config to the mux - ts.Config = m.Server - ts.Start() + // Start serving requests in a goroutine + go m.ListenAndServe("", "") - // Create a ListenerMux. - lm := &ListenerMux{ - Listener: ts.Listener, - config: &tls.Config{}, - cond: sync.NewCond(&sync.Mutex{}), - } - m.listeners = []*ListenerMux{lm} - - dial := func() net.Conn { - c, cerr := net.Dial("tcp", ts.Listener.Addr().String()) - if cerr != nil { - t.Fatal(cerr) + // Dial, try until 5 times before declaring a failure + dial := func() (net.Conn, error) { + var c net.Conn + var err error + for i := 0; i < 5; i++ { + // Sleep one second in case of the server is not ready yet + time.Sleep(1 * time.Second) + // Check if there is at least one listener configured + m.mu.Lock() + if len(m.listeners) == 0 { + m.mu.Unlock() + continue + } + m.mu.Unlock() + // Run the actual Dial + m.mu.Lock() + c, err = net.Dial("tcp", m.listeners[0].Addr().String()) + m.mu.Unlock() + if err != nil { + continue + } } - return c + return c, err } // Dial to open a StateNew but don't send anything - cnew := dial() + cnew, err := dial() + if err != nil { + t.Fatal(err) + } defer cnew.Close() // Dial another connection but idle after a request to have StateIdle - cidle := dial() + cidle, err := dial() + if err != nil { + t.Fatal(err) + } defer cidle.Close() + cidle.Write([]byte("HEAD / HTTP/1.1\r\nHost: foo\r\n\r\n")) - _, err := http.ReadResponse(bufio.NewReader(cidle), nil) + _, err = http.ReadResponse(bufio.NewReader(cidle), nil) if err != nil { t.Fatal(err) } // Make sure we don't block forever. m.Close() - - // Make sure there are zero connections - m.mu.Lock() - if len(m.conns) > 0 { - t.Fatal("Should have 0 connections") - } - m.mu.Unlock() } -func TestListenAndServePlain(t *testing.T) { +func TestServerListenAndServePlain(t *testing.T) { wait := make(chan struct{}) addr := net.JoinHostPort("127.0.0.1", getFreePort()) errc := make(chan error) @@ -295,8 +292,6 @@ func TestListenAndServePlain(t *testing.T) { // Initialize done channel specifically for each tests. globalServiceDoneCh = make(chan struct{}, 1) - // Initialize signal channel specifically for each tests. - globalServiceSignalCh = make(chan serviceSignal, 1) // Create ServerMux and when we receive a request we stop waiting m := NewServerMux(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -337,7 +332,7 @@ func TestListenAndServePlain(t *testing.T) { } } -func TestListenAndServeTLS(t *testing.T) { +func TestServerListenAndServeTLS(t *testing.T) { wait := make(chan struct{}) addr := net.JoinHostPort("127.0.0.1", getFreePort()) errc := make(chan error) diff --git a/cmd/server-rlimit-nix.go b/cmd/server-rlimit-nix.go index 9c0b73f00..03341a6b1 100644 --- a/cmd/server-rlimit-nix.go +++ b/cmd/server-rlimit-nix.go @@ -1,4 +1,4 @@ -// +build !windows,!plan9 +// +build !windows,!plan9,!openbsd /* * Minio Cloud Storage, (C) 2016 Minio, Inc. diff --git a/cmd/server-rlimit-openbsd.go b/cmd/server-rlimit-openbsd.go new file mode 100644 index 000000000..16030447e --- /dev/null +++ b/cmd/server-rlimit-openbsd.go @@ -0,0 +1,83 @@ +// +build openbsd + +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmd + +import ( + "syscall" + + "github.com/minio/minio/pkg/sys" +) + +// For all unixes we need to bump allowed number of open files to a +// higher value than its usual default of '1024'. The reasoning is +// that this value is too small for a server. +func setMaxOpenFiles() error { + var rLimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err != nil { + return err + } + // Set the current limit to Max, it is usually around 4096. + // TO increase this limit further user has to manually edit + // `/etc/security/limits.conf` + rLimit.Cur = rLimit.Max + return syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) +} + +// Set max memory used by minio as a process, this value is usually +// set to 'unlimited' but we need to validate additionally to verify +// if any hard limit is set by the user, in such a scenario would need +// to reset the global max cache size to be 80% of the hardlimit set +// by the user. This is done to honor the system limits and not crash. +func setMaxMemory() error { + var rLimit syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_DATA, &rLimit) + if err != nil { + return err + } + // Set the current limit to Max, it is default 'unlimited'. + // TO decrease this limit further user has to manually edit + // `/etc/security/limits.conf` + rLimit.Cur = rLimit.Max + err = syscall.Setrlimit(syscall.RLIMIT_DATA, &rLimit) + if err != nil { + return err + } + err = syscall.Getrlimit(syscall.RLIMIT_DATA, &rLimit) + if err != nil { + return err + } + // Validate if rlimit memory is set to lower + // than max cache size. Then we should use such value. + if uint64(rLimit.Cur) < globalMaxCacheSize { + globalMaxCacheSize = uint64(float64(50*rLimit.Cur) / 100) + } + + // Make sure globalMaxCacheSize is less than RAM size. + stats, err := sys.GetStats() + if err != nil && err != sys.ErrNotImplemented { + return err + } + // If TotalRAM is >= minRAMSize we proceed to enable cache. + // cache is always 50% of the totalRAM. + if err == nil && stats.TotalRAM >= minRAMSize { + globalMaxCacheSize = uint64(float64(50*stats.TotalRAM) / 100) + } + return nil +} diff --git a/cmd/server-startup-msg.go b/cmd/server-startup-msg.go index 0cb7370de..53718aa74 100644 --- a/cmd/server-startup-msg.go +++ b/cmd/server-startup-msg.go @@ -101,10 +101,12 @@ func printEventNotifiers() { return } arnMsg := colorBlue("SQS ARNs: ") - if len(globalEventNotifier.external.targets) == 0 { + // Get all configured external notification targets + externalTargets := globalEventNotifier.GetAllExternalTargets() + if len(externalTargets) == 0 { arnMsg += colorBold(fmt.Sprintf(getFormatStr(len(""), 1), "")) } - for queueArn := range globalEventNotifier.external.targets { + for queueArn := range externalTargets { arnMsg += colorBold(fmt.Sprintf(getFormatStr(len(queueArn), 1), queueArn)) } console.Println(arnMsg) @@ -141,7 +143,7 @@ func getStorageInfoMsg(storageInfo StorageInfo) string { msg := fmt.Sprintf("%s %s Free, %s Total", colorBlue("Drive Capacity:"), humanize.IBytes(uint64(storageInfo.Free)), humanize.IBytes(uint64(storageInfo.Total))) - if storageInfo.Backend.Type == XL { + if storageInfo.Backend.Type == Erasure { diskInfo := fmt.Sprintf(" %d Online, %d Offline. ", storageInfo.Backend.OnlineDisks, storageInfo.Backend.OfflineDisks) if maxDiskFailures := storageInfo.Backend.ReadQuorum - storageInfo.Backend.OfflineDisks; maxDiskFailures >= 0 { diskInfo += fmt.Sprintf("We can withstand [%d] more drive failure(s).", maxDiskFailures) diff --git a/cmd/server-startup-msg_test.go b/cmd/server-startup-msg_test.go index bd15cd1e4..ef39b9e18 100644 --- a/cmd/server-startup-msg_test.go +++ b/cmd/server-startup-msg_test.go @@ -38,7 +38,7 @@ func TestStorageInfoMsg(t *testing.T) { OfflineDisks int ReadQuorum int WriteQuorum int - }{XL, 7, 1, 4, 5}, + }{Erasure, 7, 1, 4, 5}, } if msg := getStorageInfoMsg(infoStorage); !strings.Contains(msg, "2.0 GiB Free, 10 GiB Total") || !strings.Contains(msg, "7 Online, 1 Offline") { diff --git a/cmd/server-startup-utils.go b/cmd/server-startup-utils.go index aef08e2b6..f19164595 100644 --- a/cmd/server-startup-utils.go +++ b/cmd/server-startup-utils.go @@ -19,7 +19,6 @@ package cmd import ( "fmt" "net" - "net/http" ) // getListenIPs - gets all the ips to listen on. @@ -49,7 +48,7 @@ func getListenIPs(serverAddr string) (hosts []string, port string, err error) { } // Finalizes the API endpoints based on the host list and port. -func finalizeAPIEndpoints(apiServer *http.Server) (endPoints []string, err error) { +func finalizeAPIEndpoints(addr string) (endPoints []string, err error) { // Verify current scheme. scheme := httpScheme if globalIsSSL { @@ -57,7 +56,7 @@ func finalizeAPIEndpoints(apiServer *http.Server) (endPoints []string, err error } // Get list of listen ips and port. - hosts, port, err1 := getListenIPs(apiServer.Addr) + hosts, port, err1 := getListenIPs(addr) if err1 != nil { return nil, err1 } diff --git a/cmd/signature-v2_test.go b/cmd/signature-v2_test.go index 56cc38957..fc5b2dee9 100644 --- a/cmd/signature-v2_test.go +++ b/cmd/signature-v2_test.go @@ -119,17 +119,13 @@ func TestDoesPresignedV2SignatureMatch(t *testing.T) { // TestValidateV2AuthHeader - Tests validate the logic of V2 Authorization header validator. func TestValidateV2AuthHeader(t *testing.T) { - // Initialize server config. - if _, err := initConfig(); err != nil { - t.Fatal(err) + root, err := newTestConfig(globalMinioDefaultRegion) + if err != nil { + t.Fatal("Unable to initialize test config.") } + defer removeAll(root) - // Save config. - if err := serverConfig.Save(); err != nil { - t.Fatal(err) - } accessID := serverConfig.GetCredential().AccessKey - testCases := []struct { authString string expectedError APIErrorCode @@ -194,13 +190,11 @@ func TestValidateV2AuthHeader(t *testing.T) { } func TestDoesPolicySignatureV2Match(t *testing.T) { - if _, err := initConfig(); err != nil { - t.Fatal(err) - } - - if err := serverConfig.Save(); err != nil { - t.Fatal(err) + root, err := newTestConfig(globalMinioDefaultRegion) + if err != nil { + t.Fatal("Unable to initialize test config.") } + defer removeAll(root) creds := serverConfig.GetCredential() policy := "policy" testCases := []struct { diff --git a/cmd/signature-v4-parser.go b/cmd/signature-v4-parser.go index 913099e47..475361fa4 100644 --- a/cmd/signature-v4-parser.go +++ b/cmd/signature-v4-parser.go @@ -34,6 +34,16 @@ type credentialHeader struct { } } +// Return scope string. +func (c credentialHeader) getScope() string { + return strings.Join([]string{ + c.scope.date.Format(yyyymmdd), + c.scope.region, + c.scope.service, + c.scope.request, + }, "/") +} + // parse credentialHeader string into its structured form. func parseCredentialHeader(credElement string) (credentialHeader, APIErrorCode) { creds := strings.Split(strings.TrimSpace(credElement), "=") diff --git a/cmd/signature-v4.go b/cmd/signature-v4.go index 174e7579d..f6a5ea2fb 100644 --- a/cmd/signature-v4.go +++ b/cmd/signature-v4.go @@ -124,9 +124,9 @@ func getScope(t time.Time, region string) string { } // getStringToSign a string based on selected query values. -func getStringToSign(canonicalRequest string, t time.Time, region string) string { +func getStringToSign(canonicalRequest string, t time.Time, scope string) string { stringToSign := signV4Algorithm + "\n" + t.Format(iso8601Format) + "\n" - stringToSign = stringToSign + getScope(t, region) + "\n" + stringToSign = stringToSign + scope + "\n" canonicalRequestBytes := sha256.Sum256([]byte(canonicalRequest)) stringToSign = stringToSign + hex.EncodeToString(canonicalRequestBytes[:]) return stringToSign @@ -182,14 +182,8 @@ func doesPolicySignatureV4Match(formValues map[string]string) APIErrorCode { return ErrInvalidRegion } - // Parse date string. - t, e := time.Parse(iso8601Format, formValues["X-Amz-Date"]) - if e != nil { - return ErrMalformedDate - } - // Get signing key. - signingKey := getSigningKey(cred.SecretKey, t, region) + signingKey := getSigningKey(cred.SecretKey, credHeader.scope.date, region) // Get signature. newSignature := getSignature(signingKey, formValues["Policy"]) @@ -311,10 +305,10 @@ func doesPresignedSignatureMatch(hashedPayload string, r *http.Request, region s presignedCanonicalReq := getCanonicalRequest(extractedSignedHeaders, hashedPayload, encodedQuery, req.URL.Path, req.Method, req.Host) // Get string to sign from canonical request. - presignedStringToSign := getStringToSign(presignedCanonicalReq, t, region) + presignedStringToSign := getStringToSign(presignedCanonicalReq, t, pSignValues.Credential.getScope()) // Get hmac presigned signing key. - presignedSigningKey := getSigningKey(cred.SecretKey, t, region) + presignedSigningKey := getSigningKey(cred.SecretKey, pSignValues.Credential.scope.date, region) // Get new signature. newSignature := getSignature(presignedSigningKey, presignedStringToSign) @@ -408,10 +402,10 @@ func doesSignatureMatch(hashedPayload string, r *http.Request, region string) AP canonicalRequest := getCanonicalRequest(extractedSignedHeaders, hashedPayload, queryStr, req.URL.Path, req.Method, req.Host) // Get string to sign from canonical request. - stringToSign := getStringToSign(canonicalRequest, t, region) + stringToSign := getStringToSign(canonicalRequest, t, signV4Values.Credential.getScope()) // Get hmac signing key. - signingKey := getSigningKey(cred.SecretKey, t, region) + signingKey := getSigningKey(cred.SecretKey, signV4Values.Credential.scope.date, region) // Calculate signature. newSignature := getSignature(signingKey, stringToSign) diff --git a/cmd/signature-v4_test.go b/cmd/signature-v4_test.go index 4990f9941..12137d1e1 100644 --- a/cmd/signature-v4_test.go +++ b/cmd/signature-v4_test.go @@ -61,14 +61,7 @@ func TestDoesPolicySignatureMatch(t *testing.T) { }, expected: ErrInvalidRegion, }, - // (3) It should fail if the date is invalid (or missing, in this case). - { - form: map[string]string{ - "X-Amz-Credential": fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion), - }, - expected: ErrMalformedDate, - }, - // (4) It should fail with a bad signature. + // (3) It should fail with a bad signature. { form: map[string]string{ "X-Amz-Credential": fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion), @@ -78,7 +71,7 @@ func TestDoesPolicySignatureMatch(t *testing.T) { }, expected: ErrSignatureDoesNotMatch, }, - // (5) It should succeed if everything is correct. + // (4) It should succeed if everything is correct. { form: map[string]string{ "X-Amz-Credential": fmt.Sprintf(credentialTemplate, accessKey, now.Format(yyyymmdd), globalMinioDefaultRegion), diff --git a/cmd/stats.go b/cmd/stats.go new file mode 100644 index 000000000..9dc691839 --- /dev/null +++ b/cmd/stats.go @@ -0,0 +1,129 @@ +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmd + +import ( + "net/http" + "sync/atomic" +) + +// counter - simplify atomic counting +type counter struct { + val uint64 +} + +// Inc increases counter atomically +func (c *counter) Inc(n uint64) { + atomic.AddUint64(&c.val, n) +} + +// Value fetches counter's value atomically +func (c *counter) Value() uint64 { + return atomic.LoadUint64(&c.val) +} + +// ConnStats - Network statistics +// Count total input/output transferred bytes during +// the server's life. +type ConnStats struct { + totalInputBytes counter + totalOutputBytes counter +} + +// Increase total input bytes +func (s *ConnStats) incInputBytes(n int) { + s.totalInputBytes.Inc(uint64(n)) +} + +// Increase total output bytes +func (s *ConnStats) incOutputBytes(n int) { + s.totalOutputBytes.Inc(uint64(n)) +} + +// Return total input bytes +func (s *ConnStats) getTotalInputBytes() uint64 { + return s.totalInputBytes.Value() +} + +// Return total output bytes +func (s *ConnStats) getTotalOutputBytes() uint64 { + return s.totalOutputBytes.Value() +} + +// Prepare new ConnStats structure +func newConnStats() *ConnStats { + return &ConnStats{} +} + +// httpStats holds statistics information about +// HTTP requests made by all clients +type httpStats struct { + // HEAD request stats + totalHEADs counter + successHEADs counter + // GET request stats + totalGETs counter + successGETs counter + // PUT request + totalPUTs counter + successPUTs counter + // POST request + totalPOSTs counter + successPOSTs counter + // DELETE request + totalDELETEs counter + successDELETEs counter +} + +// Update statistics from http request and response data +func (st *httpStats) updateStats(r *http.Request, w *httpResponseRecorder) { + // A successful request has a 2xx response code + successReq := (w.respStatusCode >= 200 && w.respStatusCode < 300) + // Update stats according to method verb + switch r.Method { + case "HEAD": + st.totalHEADs.Inc(1) + if successReq { + st.successHEADs.Inc(1) + } + case "GET": + st.totalGETs.Inc(1) + if successReq { + st.successGETs.Inc(1) + } + case "PUT": + st.totalPUTs.Inc(1) + if successReq { + st.successPUTs.Inc(1) + } + case "POST": + st.totalPOSTs.Inc(1) + if successReq { + st.successPOSTs.Inc(1) + } + case "DELETE": + st.totalDELETEs.Inc(1) + if successReq { + st.successDELETEs.Inc(1) + } + } +} + +// Prepare new HttpStats structure +func newHTTPStats() *httpStats { + return &httpStats{} +} diff --git a/cmd/storage-rpc-client.go b/cmd/storage-rpc-client.go index ebe62e35d..4020b6382 100644 --- a/cmd/storage-rpc-client.go +++ b/cmd/storage-rpc-client.go @@ -23,6 +23,7 @@ import ( "net/rpc" "net/url" "path" + "strings" "github.com/minio/minio/pkg/disk" ) @@ -132,20 +133,20 @@ func newStorageRPC(ep *url.URL) (StorageAPI, error) { // Stringer interface compatible representation of network device. func (n *networkStorage) String() string { - return n.rpcClient.ServerAddr() + ":" + n.rpcClient.ServiceEndpoint() + // Remove the storage RPC path prefix, internal paths are meaningless. + serviceEndpoint := strings.TrimPrefix(n.rpcClient.ServiceEndpoint(), storageRPCPath) + return n.rpcClient.ServerAddr() + ":" + serviceEndpoint } // Init - attempts a login to reconnect. func (n *networkStorage) Init() error { - err := n.rpcClient.Login() - return toStorageErr(err) + return toStorageErr(n.rpcClient.Login()) } // Closes the underlying RPC connection. -func (n *networkStorage) Close() (err error) { +func (n *networkStorage) Close() error { // Close the underlying connection. - err = n.rpcClient.Close() - return toStorageErr(err) + return toStorageErr(n.rpcClient.Close()) } // DiskInfo - fetch disk information for a remote disk. diff --git a/cmd/streaming-signature-v4.go b/cmd/streaming-signature-v4.go index d2bbc3d66..9383c17a0 100644 --- a/cmd/streaming-signature-v4.go +++ b/cmd/streaming-signature-v4.go @@ -135,10 +135,10 @@ func calculateSeedSignature(r *http.Request) (signature string, date time.Time, canonicalRequest := getCanonicalRequest(extractedSignedHeaders, payload, queryStr, req.URL.Path, req.Method, req.Host) // Get string to sign from canonical request. - stringToSign := getStringToSign(canonicalRequest, date, region) + stringToSign := getStringToSign(canonicalRequest, date, signV4Values.Credential.getScope()) // Get hmac signing key. - signingKey := getSigningKey(cred.SecretKey, date, region) + signingKey := getSigningKey(cred.SecretKey, signV4Values.Credential.scope.date, region) // Calculate signature. newSignature := getSignature(signingKey, stringToSign) @@ -221,6 +221,7 @@ const ( readChunkTrailer readChunk verifyChunk + eofChunk ) func (cs chunkState) String() string { @@ -234,6 +235,9 @@ func (cs chunkState) String() string { stateString = "readChunk" case verifyChunk: stateString = "verifyChunk" + case eofChunk: + stateString = "eofChunk" + } return stateString } @@ -309,10 +313,13 @@ func (cr *s3ChunkedReader) Read(buf []byte) (n int, err error) { // this follows the chaining. cr.seedSignature = newSignature cr.chunkSHA256Writer.Reset() - cr.state = readChunkHeader if cr.lastChunk { - return n, nil + cr.state = eofChunk + } else { + cr.state = readChunkHeader } + case eofChunk: + return n, io.EOF } } } diff --git a/cmd/test-utils_test.go b/cmd/test-utils_test.go index a9c544576..7ef2f25b2 100644 --- a/cmd/test-utils_test.go +++ b/cmd/test-utils_test.go @@ -496,6 +496,10 @@ func resetGlobalIsXL() { globalIsXL = false } +func resetGlobalIsEnvs() { + globalIsEnvCreds = false +} + // Resets all the globals used modified in tests. // Resetting ensures that the changes made to globals by one test doesn't affect others. func resetTestGlobals() { @@ -513,6 +517,8 @@ func resetTestGlobals() { resetGlobalEndpoints() // Reset global isXL flag. resetGlobalIsXL() + // Reset global isEnvCreds flag. + resetGlobalIsEnvs() } // Configure the server for the test run. @@ -527,7 +533,7 @@ func newTestConfig(bucketLocation string) (rootPath string, err error) { setGlobalConfigPath(rootPath) // Initialize server config. - if _, err = initConfig(); err != nil { + if err = newConfig(credential{}); err != nil { return "", err } @@ -893,7 +899,8 @@ func preSignV4(req *http.Request, accessKeyID, secretAccessKey string, expires i region := serverConfig.GetRegion() date := time.Now().UTC() - credential := fmt.Sprintf("%s/%s", accessKeyID, getScope(date, region)) + scope := getScope(date, region) + credential := fmt.Sprintf("%s/%s", accessKeyID, scope) // Set URL query. query := req.URL.Query() @@ -909,7 +916,7 @@ func preSignV4(req *http.Request, accessKeyID, secretAccessKey string, expires i queryStr := strings.Replace(query.Encode(), "+", "%20", -1) canonicalRequest := getCanonicalRequest(extractedSignedHeaders, unsignedPayload, queryStr, req.URL.Path, req.Method, req.Host) - stringToSign := getStringToSign(canonicalRequest, date, region) + stringToSign := getStringToSign(canonicalRequest, date, scope) signingKey := getSigningKey(secretAccessKey, date, region) signature := getSignature(signingKey, stringToSign) @@ -1419,6 +1426,13 @@ func getPutObjectPartURL(endPoint, bucketName, objectName, uploadID, partNumber return makeTestTargetURL(endPoint, bucketName, objectName, queryValues) } +func getCopyObjectPartURL(endPoint, bucketName, objectName, uploadID, partNumber string) string { + queryValues := url.Values{} + queryValues.Set("uploadId", uploadID) + queryValues.Set("partNumber", partNumber) + return makeTestTargetURL(endPoint, bucketName, objectName, queryValues) +} + // return URL for fetching object from the bucket. func getGetObjectURL(endPoint, bucketName, objectName string) string { return makeTestTargetURL(endPoint, bucketName, objectName, url.Values{}) @@ -1782,6 +1796,7 @@ func ExecObjectLayerAPIAnonTest(t *testing.T, testName, bucketName, objectName, failTestStr := func(testType, failMsg string) string { return fmt.Sprintf("Minio %s: %s fail for \"%s\": \n %s", instanceType, testType, testName, failMsg) } + // httptest Recorder to capture all the response by the http handler. rec := httptest.NewRecorder() // reading the body to preserve it so that it can be used again for second attempt of sending unsigned HTTP request. @@ -1883,22 +1898,22 @@ func ExecObjectLayerAPIAnonTest(t *testing.T, testName, bucketName, objectName, } } -// ExecObjectLayerAPINilTest - Sets the object layer to `nil`, and calls rhe registered object layer API endpoint, and assert the error response. -// The purpose is to validate the API handlers response when the object layer is uninitialized. -// Usage hint: Should be used at the end of the API end points tests (ex: check the last few lines of `testAPIListObjectPartsHandler`), need a sample HTTP request -// to be sent as argument so that the relevant handler is called, -// the handler registration is expected to be done since its called from within the API handler tests, -// the reference to the registered HTTP handler has to be sent as an argument. +// ExecObjectLayerAPINilTest - Sets the object layer to `nil`, and calls rhe registered object layer API endpoint, +// and assert the error response. The purpose is to validate the API handlers response when the object layer is uninitialized. +// Usage hint: Should be used at the end of the API end points tests (ex: check the last few lines of `testAPIListObjectPartsHandler`), +// need a sample HTTP request to be sent as argument so that the relevant handler is called, the handler registration is expected +// to be done since its called from within the API handler tests, the reference to the registered HTTP handler has to be sent +// as an argument. func ExecObjectLayerAPINilTest(t TestErrHandler, bucketName, objectName, instanceType string, apiRouter http.Handler, req *http.Request) { // httptest Recorder to capture all the response by the http handler. rec := httptest.NewRecorder() // The API handler gets the referece to the object layer via the global object Layer, // setting it to `nil` in order test for handlers response for uninitialized object layer. - globalObjLayerMutex.Lock() globalObjectAPI = nil globalObjLayerMutex.Unlock() + // call the HTTP handler. apiRouter.ServeHTTP(rec, req) @@ -1909,7 +1924,8 @@ func ExecObjectLayerAPINilTest(t TestErrHandler, bucketName, objectName, instanc t.Errorf("Object API Nil Test expected to fail with %d, but failed with %d", serverNotInitializedErr, rec.Code) } // expected error response in bytes when objectLayer is not initialized, or set to `nil`. - expectedErrResponse := encodeResponse(getAPIErrorResponse(getAPIError(ErrServerNotInitialized), getGetObjectURL("", bucketName, objectName))) + expectedErrResponse := encodeResponse(getAPIErrorResponse(getAPIError(ErrServerNotInitialized), + getGetObjectURL("", bucketName, objectName))) // HEAD HTTP Request doesn't contain body in its response, // for other type of HTTP requests compare the response body content with the expected one. @@ -1932,8 +1948,10 @@ func ExecObjectLayerAPITest(t *testing.T, objAPITest objAPITestType, endpoints [ // reset globals. // this is to make sure that the tests are not affected by modified value. resetTestGlobals() + // initialize NSLock. initNSLock(false) + // initialize the server and obtain the credentials and root. // credentials are necessary to sign the HTTP request. rootPath, err := newTestConfig(globalMinioDefaultRegion) @@ -2016,6 +2034,7 @@ func ExecObjectLayerDiskAlteredTest(t *testing.T, objTest objTestDiskNotFoundTyp if err != nil { t.Fatalf("Initialization of object layer failed for XL setup: %s", err) } + // Executing the object layer tests for XL. objTest(objLayer, XLTestStr, fsDirs, t) defer removeRoots(fsDirs) @@ -2093,6 +2112,9 @@ func registerBucketLevelFunc(bucket *router.Router, api objectAPIHandlers, apiFu case "NewMultipart": // Register New Multipart upload handler. bucket.Methods("POST").Path("/{object:.+}").HandlerFunc(api.NewMultipartUploadHandler).Queries("uploads", "") + case "CopyObjectPart": + // Register CopyObjectPart handler. + bucket.Methods("PUT").Path("/{object:.+}").HeadersRegexp("X-Amz-Copy-Source", ".*?(\\/|%2F).*?").HandlerFunc(api.CopyObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") case "PutObjectPart": // Register PutObjectPart handler. bucket.Methods("PUT").Path("/{object:.+}").HandlerFunc(api.PutObjectPartHandler).Queries("partNumber", "{partNumber:[0-9]+}", "uploadId", "{uploadId:.*}") diff --git a/cmd/posix-utils_common.go b/cmd/to_err_test.go similarity index 53% rename from cmd/posix-utils_common.go rename to cmd/to_err_test.go index ea15b8bca..2311b3619 100644 --- a/cmd/posix-utils_common.go +++ b/cmd/to_err_test.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2016 Minio, Inc. + * Minio Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,16 @@ package cmd -import "strings" +import "testing" -// List of reserved words for files, includes old and new ones. -var posixReservedPrefix = []string{ - "$tmpfile", - // Add new reserved words if any used in future. -} - -// hasPosixReservedPrefix - has reserved prefix. -func hasPosixReservedPrefix(name string) (isReserved bool) { - for _, reservedKey := range posixReservedPrefix { - if strings.HasPrefix(name, reservedKey) { - isReserved = true - break - } +func TestToErrIsNil(t *testing.T) { + if toObjectErr(nil) != nil { + t.Errorf("Test expected to return nil, failed instead got a non-nil value %s", toObjectErr(nil)) + } + if toStorageErr(nil) != nil { + t.Errorf("Test expected to return nil, failed instead got a non-nil value %s", toStorageErr(nil)) + } + if toAPIErrorCode(nil) != ErrNone { + t.Errorf("Test expected error code to be ErrNone, failed instead provided %d", toAPIErrorCode(nil)) } - - return isReserved } diff --git a/cmd/tree-walk.go b/cmd/tree-walk.go index 92cfb8578..05c78b0cd 100644 --- a/cmd/tree-walk.go +++ b/cmd/tree-walk.go @@ -67,7 +67,7 @@ func filterMatchingPrefix(entries []string, prefixEntry string) []string { if start == end { break } - if strings.HasPrefix(entries[start], prefixEntry) { + if hasPrefix(entries[start], prefixEntry) { break } start++ @@ -76,7 +76,7 @@ func filterMatchingPrefix(entries []string, prefixEntry string) []string { if start == end { break } - if strings.HasPrefix(entries[end-1], prefixEntry) { + if hasPrefix(entries[end-1], prefixEntry) { break } end-- @@ -95,53 +95,30 @@ type listDirFunc func(bucket, prefixDir, prefixEntry string) (entries []string, // 4. XL backend multipart listing - isLeaf is true if the entry is a directory and contains uploads.json type isLeafFunc func(string, string) bool -// Returns function "listDir" of the type listDirFunc. -// isLeaf - is used by listDir function to check if an entry is a leaf or non-leaf entry. -// disks - used for doing disk.ListDir(). FS passes single disk argument, XL passes a list of disks. -func listDirFactory(isLeaf isLeafFunc, treeWalkIgnoredErrs []error, disks ...StorageAPI) listDirFunc { - // listDir - lists all the entries at a given prefix and given entry in the prefix. - listDir := func(bucket, prefixDir, prefixEntry string) (entries []string, delayIsLeaf bool, err error) { - for _, disk := range disks { - if disk == nil { - continue - } - entries, err = disk.ListDir(bucket, prefixDir) - if err == nil { - // Listing needs to be sorted. - sort.Strings(entries) +func filterListEntries(bucket, prefixDir string, entries []string, prefixEntry string, isLeaf isLeafFunc) ([]string, bool) { + // Listing needs to be sorted. + sort.Strings(entries) - // Filter entries that have the prefix prefixEntry. - entries = filterMatchingPrefix(entries, prefixEntry) + // Filter entries that have the prefix prefixEntry. + entries = filterMatchingPrefix(entries, prefixEntry) - // Can isLeaf() check be delayed till when it has to be sent down the - // treeWalkResult channel? - delayIsLeaf = delayIsLeafCheck(entries) - if delayIsLeaf { - return entries, delayIsLeaf, nil - } - - // isLeaf() check has to happen here so that trailing "/" for objects can be removed. - for i, entry := range entries { - if isLeaf(bucket, pathJoin(prefixDir, entry)) { - entries[i] = strings.TrimSuffix(entry, slashSeparator) - } - } - // Sort again after removing trailing "/" for objects as the previous sort - // does not hold good anymore. - sort.Strings(entries) - return entries, delayIsLeaf, nil - } - // For any reason disk was deleted or goes offline, continue - // and list from other disks if possible. - if isErrIgnored(err, treeWalkIgnoredErrs...) { - continue - } - break - } - // Return error at the end. - return nil, false, traceError(err) + // Can isLeaf() check be delayed till when it has to be sent down the + // treeWalkResult channel? + delayIsLeaf := delayIsLeafCheck(entries) + if delayIsLeaf { + return entries, true } - return listDir + + // isLeaf() check has to happen here so that trailing "/" for objects can be removed. + for i, entry := range entries { + if isLeaf(bucket, pathJoin(prefixDir, entry)) { + entries[i] = strings.TrimSuffix(entry, slashSeparator) + } + } + // Sort again after removing trailing "/" for objects as the previous sort + // does not hold good anymore. + sort.Strings(entries) + return entries, false } // treeWalk walks directory tree recursively pushing treeWalkResult into the channel as and when it encounters files. @@ -196,7 +173,7 @@ func doTreeWalk(bucket, prefixDir, entryPrefixMatch, marker string, recursive bo // Skip as the marker would already be listed in the previous listing. continue } - if recursive && !strings.HasSuffix(entry, slashSeparator) { + if recursive && !hasSuffix(entry, slashSeparator) { // We should not skip for recursive listing and if markerDir is a directory // for ex. if marker is "four/five.txt" markerDir will be "four/" which // should not be skipped, instead it will need to be treeWalk()'ed into. @@ -205,7 +182,7 @@ func doTreeWalk(bucket, prefixDir, entryPrefixMatch, marker string, recursive bo continue } } - if recursive && strings.HasSuffix(entry, slashSeparator) { + if recursive && hasSuffix(entry, slashSeparator) { // If the entry is a directory, we will need recurse into it. markerArg := "" if entry == markerDir { diff --git a/cmd/tree-walk_test.go b/cmd/tree-walk_test.go index 939439f2f..9490c6c56 100644 --- a/cmd/tree-walk_test.go +++ b/cmd/tree-walk_test.go @@ -135,7 +135,7 @@ func testTreeWalkPrefix(t *testing.T, listDir listDirFunc, isLeaf isLeafFunc) { // Check if all entries received on the channel match the prefix. for res := range twResultCh { - if !strings.HasPrefix(res.entry, prefix) { + if !hasPrefix(res.entry, prefix) { t.Errorf("Entry %s doesn't match prefix %s", res.entry, prefix) } } diff --git a/cmd/typed-errors.go b/cmd/typed-errors.go index e79ab0dd6..5a7568568 100644 --- a/cmd/typed-errors.go +++ b/cmd/typed-errors.go @@ -33,6 +33,9 @@ var errContentSHA256Mismatch = errors.New("Content checksum SHA256 mismatch") // used when we deal with data larger than expected var errSizeUnexpected = errors.New("Data size larger than expected") +// used when we deal with data with unknown size +var errSizeUnspecified = errors.New("Data size is unspecified") + // When upload object size is greater than 5G in a single PUT/POST operation. var errDataTooLarge = errors.New("Object size larger than allowed limit") diff --git a/cmd/update-main.go b/cmd/update-main.go index b301c1520..4876f9849 100644 --- a/cmd/update-main.go +++ b/cmd/update-main.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ package cmd import ( "bytes" - "errors" + "fmt" "io/ioutil" "net/http" "os" @@ -36,7 +36,16 @@ var updateCmd = cli.Command{ Name: "update", Usage: "Check for a new software update.", Action: mainUpdate, - Flags: globalFlags, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "help, h", + Usage: "Show this help.", + }, + cli.BoolFlag{ + Name: "quiet", + Usage: "Disable any update messages.", + }, + }, CustomHelpTemplate: `Name: minio {{.Name}} - {{.Usage}} @@ -44,240 +53,217 @@ USAGE: minio {{.Name}} [FLAGS] FLAGS: - {{range .Flags}}{{.}} + {{range .VisibleFlags}}{{.}} {{end}} -EXAMPLES: - 1. Check for any new official release. - $ minio {{.Name}} -`, +EXIT STATUS: + 0 - You are already running the most recent version. + 1 - New update is available. + -1 - Error in getting update information. + +VERSION: + ` + Version + `{{"\n"}}`, } -// update URL endpoints. -const ( - minioUpdateStableURL = "https://dl.minio.io/server/minio/release" -) +const releaseTagTimeLayout = "2006-01-02T15-04-05Z" -// updateMessage container to hold update messages. -type updateMessage struct { - Update bool `json:"update"` - Download string `json:"downloadURL"` - NewerThan time.Duration `json:"newerThan"` -} +const minioReleaseURL = "https://dl.minio.io/server/minio/release/" + runtime.GOOS + "-" + runtime.GOARCH + "/" -// String colorized update message. -func (u updateMessage) String() string { - if !u.Update { - updateMessage := color.New(color.FgGreen, color.Bold).SprintfFunc() - return updateMessage("You are already running the most recent version of ‘minio’.") +func getCurrentReleaseTime(minioVersion, minioBinaryPath string) (releaseTime time.Time, err error) { + if releaseTime, err = time.Parse(time.RFC3339, minioVersion); err == nil { + return releaseTime, err } - msg := colorizeUpdateMessage(u.Download, u.NewerThan) - return msg -} -func parseReleaseData(data string) (time.Time, error) { - releaseStr := strings.Fields(data) - if len(releaseStr) < 2 { - return time.Time{}, errors.New("Update data malformed") - } - releaseDate := releaseStr[1] - releaseDateSplits := strings.SplitN(releaseDate, ".", 3) - if len(releaseDateSplits) < 3 { - return time.Time{}, (errors.New("Update data malformed")) - } - if releaseDateSplits[0] != globalMinioDefaultOwnerID { - return time.Time{}, (errors.New("Update data malformed, missing minio tag")) - } - // "OFFICIAL" tag is still kept for backward compatibility. - // We should remove this for the next release. - if releaseDateSplits[1] != "RELEASE" && releaseDateSplits[1] != "OFFICIAL" { - return time.Time{}, (errors.New("Update data malformed, missing RELEASE tag")) - } - dateSplits := strings.SplitN(releaseDateSplits[2], "T", 2) - if len(dateSplits) < 2 { - return time.Time{}, (errors.New("Update data malformed, not in modified RFC3359 form")) - } - dateSplits[1] = strings.Replace(dateSplits[1], "-", ":", -1) - date := strings.Join(dateSplits, "T") - - parsedDate, err := time.Parse(time.RFC3339, date) + // Looks like version is minio non-standard, we use minio binary's ModTime as release time. + fi, err := os.Stat(minioBinaryPath) if err != nil { - return time.Time{}, err - } - return parsedDate, nil -} - -// User Agent should always following the below style. -// Please open an issue to discuss any new changes here. -// -// Minio (OS; ARCH) APP/VER APP/VER -var ( - userAgentSuffix = "Minio/" + Version + " " + "Minio/" + ReleaseTag + " " + "Minio/" + CommitID -) - -// Check if the operating system is a docker container. -func isDocker() bool { - cgroup, err := ioutil.ReadFile("/proc/self/cgroup") - if err != nil && !os.IsNotExist(err) { - errorIf(err, "Unable to read `cgroup` file.") - } - - return bytes.Contains(cgroup, []byte("docker")) -} - -// Check if the minio server binary was built with source. -func isSourceBuild() bool { - return Version == goGetTag -} - -// Fetch the current version of the Minio server binary. -func getCurrentMinioVersion() (current time.Time, err error) { - // For development builds we check for binary modTime - // to validate against latest minio server release. - if Version != goGetTag { - // Parse current minio version into RFC3339. - current, err = time.Parse(time.RFC3339, Version) - if err != nil { - return time.Time{}, err - } - return current, nil - } // else { - // For all development builds through `go get`. - // fall back to looking for version of the build - // date of the binary itself. - var fi os.FileInfo - fi, err = os.Stat(os.Args[0]) - if err != nil { - return time.Time{}, err - } - return fi.ModTime(), nil -} - -// verify updates for releases. -func getReleaseUpdate(updateURL string, duration time.Duration) (updateMsg updateMessage, errMsg string, err error) { - // Construct a new update url. - newUpdateURLPrefix := updateURL + "/" + runtime.GOOS + "-" + runtime.GOARCH - newUpdateURL := newUpdateURLPrefix + "/minio.shasum" - - // Get the downloadURL. - var downloadURL string - if isDocker() { - downloadURL = "docker pull minio/minio" + err = fmt.Errorf("Unable to get ModTime of %s. %s", minioBinaryPath, err) } else { - switch runtime.GOOS { - case globalWindowsOSName: - // For windows. - downloadURL = newUpdateURLPrefix + "/minio.exe" - default: - // For all other operating systems. - downloadURL = newUpdateURLPrefix + "/minio" - } + releaseTime = fi.ModTime().UTC() } - // Initialize update message. - updateMsg = updateMessage{ - Download: downloadURL, + return releaseTime, err +} + +// GetCurrentReleaseTime - returns this process's release time. If it is official minio version, +// parsed version is returned else minio binary's mod time is returned. +func GetCurrentReleaseTime() (releaseTime time.Time, err error) { + return getCurrentReleaseTime(Version, os.Args[0]) +} + +func isDocker(cgroupFile string) (bool, error) { + cgroup, err := ioutil.ReadFile(cgroupFile) + if os.IsNotExist(err) { + err = nil } - // Instantiate a new client with 3 sec timeout. + return bytes.Contains(cgroup, []byte("docker")), err +} + +// IsDocker - returns if the environment is docker or not. +func IsDocker() bool { + found, err := isDocker("/proc/self/cgroup") + if err != nil { + console.Fatalf("Error in docker check: %s", err) + } + + return found +} + +func isSourceBuild(minioVersion string) bool { + _, err := time.Parse(time.RFC3339, minioVersion) + return err != nil +} + +// IsSourceBuild - returns if this binary is made from source or not. +func IsSourceBuild() bool { + return isSourceBuild(Version) +} + +// DO NOT CHANGE USER AGENT STYLE. +// The style should be +// Minio (; [; docker][; source]) Minio/ Minio/ Minio/ +// +// For any change here should be discussed by openning an issue at https://github.com/minio/minio/issues. +func getUserAgent() string { + userAgent := "Minio (" + runtime.GOOS + "; " + runtime.GOARCH + if IsDocker() { + userAgent += "; docker" + } + if IsSourceBuild() { + userAgent += "; source" + } + userAgent += ") " + " Minio/" + Version + " Minio/" + ReleaseTag + " Minio/" + CommitID + + return userAgent +} + +func downloadReleaseData(releaseChecksumURL string, timeout time.Duration) (data string, err error) { + req, err := http.NewRequest("GET", releaseChecksumURL, nil) + if err != nil { + return data, err + } + req.Header.Set("User-Agent", getUserAgent()) + client := &http.Client{ - Timeout: duration, + Timeout: timeout, } - current, err := getCurrentMinioVersion() - if err != nil { - errMsg = "Unable to fetch the current version of Minio server." - return - } - - // Initialize new request. - req, err := http.NewRequest("GET", newUpdateURL, nil) - if err != nil { - return - } - - userAgentPrefix := func() string { - prefix := "Minio (" + runtime.GOOS + "; " + runtime.GOARCH - // if its a source build. - if isSourceBuild() { - if isDocker() { - prefix = prefix + "; " + "docker; source) " - } else { - prefix = prefix + "; " + "source) " - } - return prefix - } // else { not source. - if isDocker() { - prefix = prefix + "; " + "docker) " - } else { - prefix = prefix + ") " - } - return prefix - }() - - // Set user agent. - req.Header.Set("User-Agent", userAgentPrefix+" "+userAgentSuffix) - - // Fetch new update. resp, err := client.Do(req) if err != nil { - return + return data, err + } + if resp == nil { + return data, fmt.Errorf("No response from server to download URL %s", releaseChecksumURL) } - // Verify if we have a valid http response i.e http.StatusOK. - if resp != nil { - if resp.StatusCode != http.StatusOK { - errMsg = "Failed to retrieve update notice." - err = errors.New("http status : " + resp.Status) - return + if resp.StatusCode != http.StatusOK { + return data, fmt.Errorf("Error downloading URL %s. Response: %v", releaseChecksumURL, resp.Status) + } + + dataBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return data, fmt.Errorf("Error reading response. %s", err) + } + + data = string(dataBytes) + return data, err +} + +// DownloadReleaseData - downloads release data from minio official server. +func DownloadReleaseData(timeout time.Duration) (data string, err error) { + return downloadReleaseData(minioReleaseURL+"minio.shasum", timeout) +} + +func parseReleaseData(data string) (releaseTime time.Time, err error) { + fields := strings.Fields(data) + if len(fields) != 2 { + err = fmt.Errorf("Unknown release data `%s`", data) + return releaseTime, err + } + + releaseInfo := fields[1] + if fields = strings.Split(releaseInfo, "."); len(fields) != 3 { + err = fmt.Errorf("Unknown release information `%s`", releaseInfo) + return releaseTime, err + } + + if !(fields[0] == "minio" && fields[1] == "RELEASE") { + err = fmt.Errorf("Unknown release '%s'", releaseInfo) + return releaseTime, err + } + + releaseTime, err = time.Parse(releaseTagTimeLayout, fields[2]) + if err != nil { + err = fmt.Errorf("Unknown release time format. %s", err) + } + + return releaseTime, err +} + +func getLatestReleaseTime(timeout time.Duration) (releaseTime time.Time, err error) { + data, err := DownloadReleaseData(timeout) + if err != nil { + return releaseTime, err + } + + return parseReleaseData(data) +} + +func getDownloadURL() (downloadURL string) { + if IsDocker() { + return "docker pull minio/minio" + } + + if runtime.GOOS == "windows" { + return minioReleaseURL + "minio.exe" + } + + return minioReleaseURL + "minio" +} + +func getUpdateInfo(timeout time.Duration) (older time.Duration, downloadURL string, err error) { + currentReleaseTime, err := GetCurrentReleaseTime() + if err != nil { + return older, downloadURL, err + } + + latestReleaseTime, err := getLatestReleaseTime(timeout) + if err != nil { + return older, downloadURL, err + } + + if latestReleaseTime.After(currentReleaseTime) { + older = latestReleaseTime.Sub(currentReleaseTime) + downloadURL = getDownloadURL() + } + + return older, downloadURL, nil +} + +func mainUpdate(ctx *cli.Context) { + if len(ctx.Args()) != 0 { + cli.ShowCommandHelpAndExit(ctx, "update", -1) + } + + quiet := ctx.Bool("quiet") || ctx.GlobalBool("quiet") + quietPrintln := func(args ...interface{}) { + if !quiet { + console.Println(args...) } } - // Read the response body. - updateBody, err := ioutil.ReadAll(resp.Body) + older, downloadURL, err := getUpdateInfo(10 * time.Second) if err != nil { - errMsg = "Failed to retrieve update notice. Please try again later." - return + quietPrintln(err) + os.Exit(-1) } - errMsg = "Failed to retrieve update notice. Please try again later. Please report this issue at https://github.com/minio/minio/issues" - - // Parse the date if its valid. - latest, err := parseReleaseData(string(updateBody)) - if err != nil { - return + if older != time.Duration(0) { + quietPrintln(colorizeUpdateMessage(downloadURL, older)) + os.Exit(1) } - // Verify if the date is not zero. - if latest.IsZero() { - err = errors.New("Release date cannot be zero. Please report this issue at https://github.com/minio/minio/issues") - return - } - - // Is the update latest?. - if latest.After(current) { - updateMsg.Update = true - updateMsg.NewerThan = latest.Sub(current) - } - - // Return update message. - return updateMsg, "", nil -} - -// main entry point for update command. -func mainUpdate(ctx *cli.Context) { - // Initialization routine, such as config loading, enable logging, .. - minioInit(ctx) - - if globalQuiet { - return - } - - // Check for update. - var updateMsg updateMessage - var errMsg string - var err error - var secs = time.Second * 3 - updateMsg, errMsg, err = getReleaseUpdate(minioUpdateStableURL, secs) - fatalIf(err, errMsg) - console.Println(updateMsg) + colorSprintf := color.New(color.FgGreen, color.Bold).SprintfFunc() + quietPrintln(colorSprintf("You are already running the most recent version of ‘minio’.")) + os.Exit(0) } diff --git a/cmd/update-main_nix_test.go b/cmd/update-main_nix_test.go deleted file mode 100644 index 11e1a0b77..000000000 --- a/cmd/update-main_nix_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// +build linux darwin dragonfly freebsd netbsd openbsd - -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cmd - -import ( - "fmt" - "net/http" - "net/http/httptest" - "reflect" - "runtime" - "testing" - "time" -) - -// Validate when release versions are properly set. -func TestReleaseUpdateVersion(t *testing.T) { - Version = "2016-10-06T00:08:32Z" - ReleaseTag = "RELEASE.2016-10-06T00-08-32Z" - CommitID = "d1c38ba8f0b3aecdf9b932c087dd65c21eebac33" - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z") - })) - userAgentSuffix = "Minio/" + Version + " " + "Minio/" + ReleaseTag + " " + "Minio/" + CommitID - defer ts.Close() - testCases := []struct { - updateURL string - updateMsg updateMessage - errMsg string - shouldPass bool - }{ - { - updateURL: ts.URL, - updateMsg: updateMessage{ - Download: ts.URL + "/" + runtime.GOOS + "-" + runtime.GOARCH + "/minio", - Update: true, - NewerThan: 90487000000000, - }, - errMsg: "", - shouldPass: true, - }, - } - - // Validates all the errors reported. - for i, testCase := range testCases { - updateMsg, errMsg, err := getReleaseUpdate(testCase.updateURL, time.Second*1) - if testCase.shouldPass && err != nil { - t.Errorf("Test %d: Unable to fetch release update %s", i+1, err) - } - if errMsg != testCase.errMsg { - t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.errMsg, errMsg) - } - if !reflect.DeepEqual(updateMsg, testCase.updateMsg) { - t.Errorf("Test %d: Expected %#v, got %#v", i+1, testCase.updateMsg, updateMsg) - } - } -} - -func TestReleaseUpdate(t *testing.T) { - Version = "DEVELOPMENT.GOGET" - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hello, client") - })) - defer ts.Close() - testCases := []struct { - updateURL string - updateMsg updateMessage - errMsg string - shouldPass bool - }{ - { - updateURL: ts.URL, - updateMsg: updateMessage{ - Download: ts.URL + "/" + runtime.GOOS + "-" + runtime.GOARCH + "/minio", - }, - errMsg: "Failed to retrieve update notice. Please try again later. Please report this issue at https://github.com/minio/minio/issues", - shouldPass: false, - }, - } - - // Validates all the errors reported. - for i, testCase := range testCases { - updateMsg, errMsg, err := getReleaseUpdate(testCase.updateURL, time.Second*1) - if testCase.shouldPass && err != nil { - t.Errorf("Test %d: Unable to fetch release update %s", i+1, err) - } - if errMsg != testCase.errMsg { - t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.errMsg, errMsg) - } - if !reflect.DeepEqual(updateMsg, testCase.updateMsg) { - t.Errorf("Test %d: Expected %#v, got %#v", i+1, testCase.updateMsg, updateMsg) - } - } -} diff --git a/cmd/update-main_test.go b/cmd/update-main_test.go new file mode 100644 index 000000000..364e698c5 --- /dev/null +++ b/cmd/update-main_test.go @@ -0,0 +1,275 @@ +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cmd + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "runtime" + "testing" + "time" +) + +func TestGetCurrentReleaseTime(t *testing.T) { + minioVersion1 := time.Now().UTC().Format(time.RFC3339) + releaseTime1, _ := time.Parse(time.RFC3339, minioVersion1) + + minioVersion2 := "DEVELOPMENT.GOGET" + tmpfile, err := ioutil.TempFile("", "get-current-release-time-testcase") + if err != nil { + t.Fatalf("Unable to create temporary file. %s", err) + } + defer os.Remove(tmpfile.Name()) + minioBinaryPath2 := tmpfile.Name() + fi, err := tmpfile.Stat() + if err != nil { + t.Fatalf("Unable to get temporary file info. %s", err) + } + if err = tmpfile.Close(); err != nil { + t.Fatalf("Unable to create temporary file. %s", err) + } + releaseTime2 := fi.ModTime().UTC() + + errorMessage1 := "Unable to get ModTime of . stat : no such file or directory" + if runtime.GOOS == "windows" { + errorMessage1 = "Unable to get ModTime of . Lstat : The system cannot find the path specified." + } + + errorMessage2 := "Unable to get ModTime of non-existing-file. stat non-existing-file: no such file or directory" + if runtime.GOOS == "windows" { + errorMessage2 = "Unable to get ModTime of non-existing-file. GetFileAttributesEx non-existing-file: The system cannot find the file specified." + } + + testCases := []struct { + minioVersion string + minioBinaryPath string + expectedResult time.Time + expectedErr error + }{ + {minioVersion1, "", releaseTime1, nil}, + {minioVersion1, minioBinaryPath2, releaseTime1, nil}, + {minioVersion2, minioBinaryPath2, releaseTime2, nil}, + {"junk", minioBinaryPath2, releaseTime2, nil}, + {"3.2.0", minioBinaryPath2, releaseTime2, nil}, + {minioVersion2, "", time.Time{}, fmt.Errorf(errorMessage1)}, + {"junk", "non-existing-file", time.Time{}, fmt.Errorf(errorMessage2)}, + {"3.2.0", "non-existing-file", time.Time{}, fmt.Errorf(errorMessage2)}, + } + + if runtime.GOOS == "linux" { + testCases = append(testCases, struct { + minioVersion string + minioBinaryPath string + expectedResult time.Time + expectedErr error + }{"3.2a", "/proc/1/cwd", time.Time{}, fmt.Errorf("Unable to get ModTime of /proc/1/cwd. stat /proc/1/cwd: permission denied")}) + } + + for _, testCase := range testCases { + result, err := getCurrentReleaseTime(testCase.minioVersion, testCase.minioBinaryPath) + if testCase.expectedErr == nil { + if err != nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + } else if err == nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } else if testCase.expectedErr.Error() != err.Error() { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + + if !testCase.expectedResult.Equal(result) { + t.Fatalf("result: expected: %v, got: %v", testCase.expectedResult, result) + } + } +} + +func TestIsDocker(t *testing.T) { + createTempFile := func(content string) string { + tmpfile, err := ioutil.TempFile("", "isdocker-testcase") + if err != nil { + t.Fatalf("Unable to create temporary file. %s", err) + } + if _, err = tmpfile.Write([]byte(content)); err != nil { + t.Fatalf("Unable to create temporary file. %s", err) + } + if err = tmpfile.Close(); err != nil { + t.Fatalf("Unable to create temporary file. %s", err) + } + return tmpfile.Name() + } + + filename1 := createTempFile(`11:pids:/user.slice/user-1000.slice/user@1000.service +10:blkio:/ +9:hugetlb:/ +8:perf_event:/ +7:cpuset:/ +6:devices:/user.slice +5:net_cls,net_prio:/ +4:cpu,cpuacct:/ +3:memory:/user/bala/0 +2:freezer:/user/bala/0 +1:name=systemd:/user.slice/user-1000.slice/user@1000.service/gnome-terminal-server.service +`) + defer os.Remove(filename1) + filename2 := createTempFile(`14:name=systemd:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +13:pids:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +12:hugetlb:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +11:net_prio:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +10:perf_event:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +9:net_cls:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +8:freezer:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +7:devices:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +6:memory:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +5:blkio:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +4:cpuacct:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +3:cpu:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +2:cpuset:/docker/d5eb950884d828237f60f624ff575a1a7a4daa28a8d4d750040527ed9545e727 +1:name=openrc:/docker +`) + defer os.Remove(filename2) + + testCases := []struct { + filename string + expectedResult bool + expectedErr error + }{ + {"", false, nil}, + {"/tmp/non-existing-file", false, nil}, + {filename1, false, nil}, + {filename2, true, nil}, + } + + if runtime.GOOS == "linux" { + testCases = append(testCases, struct { + filename string + expectedResult bool + expectedErr error + }{"/proc/1/cwd", false, fmt.Errorf("open /proc/1/cwd: permission denied")}) + } + + for _, testCase := range testCases { + result, err := isDocker(testCase.filename) + if testCase.expectedErr == nil { + if err != nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + } else if err == nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } else if testCase.expectedErr.Error() != err.Error() { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + + if testCase.expectedResult != result { + t.Fatalf("result: expected: %v, got: %v", testCase.expectedResult, result) + } + } +} + +func TestIsSourceBuild(t *testing.T) { + testCases := []struct { + minioVersion string + expectedResult bool + }{ + {time.Now().UTC().Format(time.RFC3339), false}, + {"DEVELOPMENT.GOGET", true}, + {"junk", true}, + {"3.2.4", true}, + } + + for _, testCase := range testCases { + result := isSourceBuild(testCase.minioVersion) + if testCase.expectedResult != result { + t.Fatalf("expected: %v, got: %v", testCase.expectedResult, result) + } + } +} + +func TestDownloadReleaseData(t *testing.T) { + httpServer1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) + defer httpServer1.Close() + httpServer2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z") + })) + defer httpServer2.Close() + httpServer3 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, "", http.StatusNotFound) + })) + defer httpServer3.Close() + + testCases := []struct { + releaseChecksumURL string + expectedResult string + expectedErr error + }{ + {httpServer1.URL, "", nil}, + {httpServer2.URL, "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n", nil}, + {httpServer3.URL, "", fmt.Errorf("Error downloading URL " + httpServer3.URL + ". Response: 404 Not Found")}, + } + + for _, testCase := range testCases { + result, err := downloadReleaseData(testCase.releaseChecksumURL, 1*time.Second) + if testCase.expectedErr == nil { + if err != nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + } else if err == nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } else if testCase.expectedErr.Error() != err.Error() { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + + if testCase.expectedResult != result { + t.Fatalf("result: expected: %v, got: %v", testCase.expectedResult, result) + } + } +} + +func TestParseReleaseData(t *testing.T) { + releaseTime, _ := time.Parse(releaseTagTimeLayout, "2016-10-07T01-16-39Z") + testCases := []struct { + data string + expectedResult time.Time + expectedErr error + }{ + {"more than two fields", time.Time{}, fmt.Errorf("Unknown release data `more than two fields`")}, + {"more than", time.Time{}, fmt.Errorf("Unknown release information `than`")}, + {"more than.two.fields", time.Time{}, fmt.Errorf("Unknown release 'than.two.fields'")}, + {"more minio.RELEASE.fields", time.Time{}, fmt.Errorf(`Unknown release time format. parsing time "fields" as "2006-01-02T15-04-05Z": cannot parse "fields" as "2006"`)}, + {"more minio.RELEASE.2016-10-07T01-16-39Z", releaseTime, nil}, + {"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n", releaseTime, nil}, + } + + for _, testCase := range testCases { + result, err := parseReleaseData(testCase.data) + if testCase.expectedErr == nil { + if err != nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + } else if err == nil { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } else if testCase.expectedErr.Error() != err.Error() { + t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err) + } + + if !testCase.expectedResult.Equal(result) { + t.Fatalf("result: expected: %v, got: %v", testCase.expectedResult, result) + } + } +} diff --git a/cmd/update-main_windows_test.go b/cmd/update-main_windows_test.go deleted file mode 100644 index 9900be556..000000000 --- a/cmd/update-main_windows_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// +build windows - -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cmd - -import ( - "fmt" - "net/http" - "net/http/httptest" - "reflect" - "runtime" - "testing" - "time" -) - -// Validate when release versions are properly set. -func TestReleaseUpdateVersion(t *testing.T) { - Version = "2016-10-06T00:08:32Z" - ReleaseTag = "RELEASE.2016-10-06T00-08-32Z" - CommitID = "d1c38ba8f0b3aecdf9b932c087dd65c21eebac33" - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z") - })) - userAgentSuffix = "Minio/" + Version + " " + "Minio/" + ReleaseTag + " " + "Minio/" + CommitID - defer ts.Close() - testCases := []struct { - updateURL string - updateMsg updateMessage - errMsg string - shouldPass bool - }{ - { - updateURL: ts.URL, - updateMsg: updateMessage{ - Download: ts.URL + "/" + runtime.GOOS + "-" + runtime.GOARCH + "/minio.exe", - Update: true, - NewerThan: 90487000000000, - }, - errMsg: "", - shouldPass: true, - }, - } - - // Validates all the errors reported. - for i, testCase := range testCases { - updateMsg, errMsg, err := getReleaseUpdate(testCase.updateURL, time.Second*1) - if testCase.shouldPass && err != nil { - t.Errorf("Test %d: Unable to fetch release update %s", i+1, err) - } - if errMsg != testCase.errMsg { - t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.errMsg, errMsg) - } - if !reflect.DeepEqual(updateMsg, testCase.updateMsg) { - t.Errorf("Test %d: Expected %#v, got %#v", i+1, testCase.updateMsg, updateMsg) - } - } -} - -func TestReleaseUpdate(t *testing.T) { - Version = "DEVELOPMENT.GOGET" - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hello, client") - })) - defer ts.Close() - testCases := []struct { - updateURL string - updateMsg updateMessage - errMsg string - shouldPass bool - }{ - { - updateURL: ts.URL, - updateMsg: updateMessage{ - Download: ts.URL + "/" + runtime.GOOS + "-" + runtime.GOARCH + "/minio.exe", - }, - errMsg: "Failed to retrieve update notice. Please try again later. Please report this issue at https://github.com/minio/minio/issues", - shouldPass: false, - }, - } - - // Validates all the errors reported. - for i, testCase := range testCases { - updateMsg, errMsg, err := getReleaseUpdate(testCase.updateURL, time.Second*1) - if testCase.shouldPass && err != nil { - t.Errorf("Test %d: Unable to fetch release update %s", i+1, err) - } - if errMsg != testCase.errMsg { - t.Errorf("Test %d: Expected %s, got %s", i+1, testCase.errMsg, errMsg) - } - if !reflect.DeepEqual(updateMsg, testCase.updateMsg) { - t.Errorf("Test %d: Expected %#v, got %#v", i+1, testCase.updateMsg, updateMsg) - } - } -} diff --git a/cmd/update-notifier_test.go b/cmd/update-notifier_test.go index b6c83e567..ff6a6408d 100644 --- a/cmd/update-notifier_test.go +++ b/cmd/update-notifier_test.go @@ -24,12 +24,11 @@ import ( // Tests update notifier string builder. func TestUpdateNotifier(t *testing.T) { - updateMsg := minioUpdateStableURL - colorUpdateMsg := colorizeUpdateMessage(updateMsg, time.Duration(72*time.Hour)) - if strings.Index(colorUpdateMsg, "minutes") == -1 { + colorUpdateMsg := colorizeUpdateMessage(minioReleaseURL, time.Duration(72*time.Hour)) + if !strings.Contains(colorUpdateMsg, "minutes") { t.Fatal("Duration string not found in colorized update message", colorUpdateMsg) } - if strings.Index(colorUpdateMsg, updateMsg) == -1 { - t.Fatal("Update message not found in colorized update message", updateMsg) + if !strings.Contains(colorUpdateMsg, minioReleaseURL) { + t.Fatal("Update message not found in colorized update message", minioReleaseURL) } } diff --git a/cmd/version-main.go b/cmd/version-main.go index 9ed543842..0ca92c52b 100644 --- a/cmd/version-main.go +++ b/cmd/version-main.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,12 @@ var versionCmd = cli.Command{ Name: "version", Usage: "Print version.", Action: mainVersion, - Flags: globalFlags, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "help, h", + Usage: "Show this help.", + }, + }, CustomHelpTemplate: `NAME: minio {{.Name}} - {{.Usage}} @@ -33,10 +38,10 @@ USAGE: minio {{.Name}} FLAGS: - {{range .Flags}}{{.}} + {{range .VisibleFlags}}{{.}} {{end}} - -`, +VERSION: + ` + Version + `{{"\n"}}`, } func mainVersion(ctx *cli.Context) { @@ -44,13 +49,6 @@ func mainVersion(ctx *cli.Context) { cli.ShowCommandHelpAndExit(ctx, "version", 1) } - // Initialization routine, such as config loading, enable logging, .. - minioInit(ctx) - - if globalQuiet { - return - } - console.Println("Version: " + Version) console.Println("Release-Tag: " + ReleaseTag) console.Println("Commit-ID: " + CommitID) diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index 8346ef944..c988ab835 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -17,6 +17,7 @@ package cmd import ( + "archive/zip" "encoding/json" "errors" "fmt" @@ -151,7 +152,7 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re if objectAPI == nil { return toJSONError(errServerNotInitialized) } - authErr := webReqestAuthenticate(r) + authErr := webRequestAuthenticate(r) if authErr != nil { return toJSONError(authErr) } @@ -177,13 +178,16 @@ func (web *webAPIHandlers) ListBuckets(r *http.Request, args *WebGenericArgs, re type ListObjectsArgs struct { BucketName string `json:"bucketName"` Prefix string `json:"prefix"` + Marker string `json:"marker"` } // ListObjectsRep - list objects response. type ListObjectsRep struct { - Objects []WebObjectInfo `json:"objects"` - Writable bool `json:"writable"` // Used by client to show "upload file" button. - UIVersion string `json:"uiVersion"` + Objects []WebObjectInfo `json:"objects"` + NextMarker string `json:"nextmarker"` + IsTruncated bool `json:"istruncated"` + Writable bool `json:"writable"` // Used by client to show "upload file" button. + UIVersion string `json:"uiVersion"` } // WebObjectInfo container for list objects metadata. @@ -208,7 +212,7 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r prefix := args.Prefix + "test" // To test if GetObject/PutObject with the specified prefix is allowed. readable := isBucketActionAllowed("s3:GetObject", args.BucketName, prefix) writable := isBucketActionAllowed("s3:PutObject", args.BucketName, prefix) - authErr := webReqestAuthenticate(r) + authErr := webRequestAuthenticate(r) switch { case authErr == errAuthentication: return toJSONError(authErr) @@ -225,30 +229,26 @@ func (web *webAPIHandlers) ListObjects(r *http.Request, args *ListObjectsArgs, r default: return errAuthentication } - marker := "" - for { - lo, err := objectAPI.ListObjects(args.BucketName, args.Prefix, marker, "/", 1000) - if err != nil { - return &json2.Error{Message: err.Error()} - } - marker = lo.NextMarker - for _, obj := range lo.Objects { - reply.Objects = append(reply.Objects, WebObjectInfo{ - Key: obj.Name, - LastModified: obj.ModTime, - Size: obj.Size, - ContentType: obj.ContentType, - }) - } - for _, prefix := range lo.Prefixes { - reply.Objects = append(reply.Objects, WebObjectInfo{ - Key: prefix, - }) - } - if !lo.IsTruncated { - break - } + lo, err := objectAPI.ListObjects(args.BucketName, args.Prefix, args.Marker, slashSeparator, 1000) + if err != nil { + return &json2.Error{Message: err.Error()} } + reply.NextMarker = lo.NextMarker + reply.IsTruncated = lo.IsTruncated + for _, obj := range lo.Objects { + reply.Objects = append(reply.Objects, WebObjectInfo{ + Key: obj.Name, + LastModified: obj.ModTime, + Size: obj.Size, + ContentType: obj.ContentType, + }) + } + for _, prefix := range lo.Prefixes { + reply.Objects = append(reply.Objects, WebObjectInfo{ + Key: prefix, + }) + } + return nil } @@ -362,18 +362,29 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se return toJSONError(errAuthentication) } + // If creds are set through ENV disallow changing credentials. + if globalIsEnvCreds { + return toJSONError(errChangeCredNotAllowed) + } + // As we already validated the authentication, we save given access/secret keys. - cred, err := getCredential(args.AccessKey, args.SecretKey) - if err != nil { + if err := validateAuthKeys(args.AccessKey, args.SecretKey); err != nil { return toJSONError(err) } + creds := credential{ + AccessKey: args.AccessKey, + SecretKey: args.SecretKey, + } + // Notify all other Minio peers to update credentials - errsMap := updateCredsOnPeers(cred) + errsMap := updateCredsOnPeers(creds) // Update local credentials - serverConfig.SetCredential(cred) - if err = serverConfig.Save(); err != nil { + serverConfig.SetCredential(creds) + + // Persist updated credentials. + if err := serverConfig.Save(); err != nil { errsMap[globalMinioAddr] = err } @@ -395,7 +406,7 @@ func (web *webAPIHandlers) SetAuth(r *http.Request, args *SetAuthArgs, reply *Se } // As we have updated access/secret key, generate new auth token. - token, err := authenticateWeb(args.AccessKey, args.SecretKey) + token, err := authenticateWeb(creds.AccessKey, creds.SecretKey) if err != nil { // Did we have peer errors? if len(errsMap) > 0 { @@ -444,7 +455,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { bucket := vars["bucket"] object := vars["object"] - authErr := webReqestAuthenticate(r) + authErr := webRequestAuthenticate(r) if authErr == errAuthentication { writeWebErrorResponse(w, errAuthentication) return @@ -454,6 +465,13 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { return } + // Require Content-Length to be set in the request + size := r.ContentLength + if size < 0 { + writeWebErrorResponse(w, errSizeUnspecified) + return + } + // Extract incoming metadata if any. metadata := extractMetadataFromHeader(r.Header) @@ -463,7 +481,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { defer objectLock.Unlock() sha256sum := "" - objInfo, err := objectAPI.PutObject(bucket, object, -1, r.Body, metadata, sha256sum) + objInfo, err := objectAPI.PutObject(bucket, object, size, r.Body, metadata, sha256sum) if err != nil { writeWebErrorResponse(w, err) return @@ -506,19 +524,97 @@ func (web *webAPIHandlers) Download(w http.ResponseWriter, r *http.Request) { objectLock.RLock() defer objectLock.RUnlock() - objInfo, err := objectAPI.GetObjectInfo(bucket, object) - if err != nil { - writeWebErrorResponse(w, err) - return - } - offset := int64(0) - err = objectAPI.GetObject(bucket, object, offset, objInfo.Size, w) - if err != nil { + if err := objectAPI.GetObject(bucket, object, 0, -1, w); err != nil { /// No need to print error, response writer already written to. return } } +// DownloadZipArgs - Argument for downloading a bunch of files as a zip file. +// JSON will look like: +// '{"bucketname":"testbucket","prefix":"john/pics/","objects":["hawaii/","maldives/","sanjose.jpg"]}' +type DownloadZipArgs struct { + Objects []string `json:"objects"` // can be files or sub-directories + Prefix string `json:"prefix"` // current directory in the browser-ui + BucketName string `json:"bucketname"` // bucket name. +} + +// Takes a list of objects and creates a zip file that sent as the response body. +func (web *webAPIHandlers) DownloadZip(w http.ResponseWriter, r *http.Request) { + objectAPI := web.ObjectAPI() + if objectAPI == nil { + writeWebErrorResponse(w, errServerNotInitialized) + return + } + + token := r.URL.Query().Get("token") + + if !isAuthTokenValid(token) { + writeWebErrorResponse(w, errAuthentication) + return + } + var args DownloadZipArgs + decodeErr := json.NewDecoder(r.Body).Decode(&args) + if decodeErr != nil { + writeWebErrorResponse(w, decodeErr) + return + } + + archive := zip.NewWriter(w) + defer archive.Close() + + for _, object := range args.Objects { + // Writes compressed object file to the response. + zipit := func(objectName string) error { + info, err := objectAPI.GetObjectInfo(args.BucketName, objectName) + if err != nil { + return err + } + header := &zip.FileHeader{ + Name: strings.TrimPrefix(objectName, args.Prefix), + Method: zip.Deflate, + UncompressedSize64: uint64(info.Size), + UncompressedSize: uint32(info.Size), + } + writer, err := archive.CreateHeader(header) + if err != nil { + writeWebErrorResponse(w, errUnexpected) + return err + } + return objectAPI.GetObject(args.BucketName, objectName, 0, info.Size, writer) + } + + if !strings.HasSuffix(object, "/") { + // If not a directory, compress the file and write it to response. + err := zipit(pathJoin(args.Prefix, object)) + if err != nil { + return + } + continue + } + + // For directories, list the contents recursively and write the objects as compressed + // date to the response writer. + marker := "" + for { + lo, err := objectAPI.ListObjects(args.BucketName, pathJoin(args.Prefix, object), marker, "", 1000) + if err != nil { + return + } + marker = lo.NextMarker + for _, obj := range lo.Objects { + err = zipit(obj.Name) + if err != nil { + return + } + } + if !lo.IsTruncated { + break + } + } + } +} + // GetBucketPolicyArgs - get bucket policy args. type GetBucketPolicyArgs struct { BucketName string `json:"bucketName"` @@ -746,7 +842,7 @@ func presignedGet(host, bucket, object string, expiry int64) string { var extractedSignedHeaders http.Header canonicalRequest := getCanonicalRequest(extractedSignedHeaders, unsignedPayload, query, path, "GET", host) - stringToSign := getStringToSign(canonicalRequest, date, region) + stringToSign := getStringToSign(canonicalRequest, date, getScope(date, region)) signingKey := getSigningKey(secretKey, date, region) signature := getSignature(signingKey, stringToSign) @@ -821,8 +917,19 @@ func toWebAPIError(err error) APIError { HTTPStatusCode: http.StatusForbidden, Description: err.Error(), } + } else if err == errSizeUnspecified { + return APIError{ + Code: "InvalidRequest", + HTTPStatusCode: http.StatusBadRequest, + Description: err.Error(), + } + } else if err == errChangeCredNotAllowed { + return APIError{ + Code: "MethodNotAllowed", + HTTPStatusCode: http.StatusMethodNotAllowed, + Description: err.Error(), + } } - // Convert error type to api error code. var apiErrCode APIErrorCode switch err.(type) { diff --git a/cmd/web-handlers_test.go b/cmd/web-handlers_test.go index 238713078..66f7cbd52 100644 --- a/cmd/web-handlers_test.go +++ b/cmd/web-handlers_test.go @@ -17,9 +17,14 @@ package cmd import ( + "archive/zip" "bytes" + "crypto/md5" + "encoding/hex" + "encoding/json" "errors" "fmt" + "io" "io/ioutil" "net/http" "net/http/httptest" @@ -128,15 +133,6 @@ func TestWebHandlerLogin(t *testing.T) { func testLoginWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() // test cases with sample input and expected output. @@ -177,15 +173,6 @@ func testStorageInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHa // get random bucket name. // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -223,15 +210,6 @@ func TestWebHandlerServerInfo(t *testing.T) { func testServerInfoWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -269,15 +247,6 @@ func TestWebHandlerMakeBucket(t *testing.T) { func testMakeBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -329,15 +298,6 @@ func TestWebHandlerListBuckets(t *testing.T) { func testListBucketsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -386,15 +346,6 @@ func TestWebHandlerListObjects(t *testing.T) { func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() rec := httptest.NewRecorder() @@ -490,15 +441,6 @@ func TestWebHandlerRemoveObject(t *testing.T) { func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() rec := httptest.NewRecorder() @@ -566,15 +508,6 @@ func TestWebHandlerGenerateAuth(t *testing.T) { func testGenerateAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() rec := httptest.NewRecorder() @@ -612,15 +545,6 @@ func TestWebHandlerSetAuth(t *testing.T) { func testSetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() rec := httptest.NewRecorder() @@ -673,15 +597,6 @@ func TestWebHandlerGetAuth(t *testing.T) { func testGetAuthWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() rec := httptest.NewRecorder() @@ -718,18 +633,9 @@ func TestWebHandlerUpload(t *testing.T) { func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() - content := []byte("temporary file's content") + content := []byte("temporary file's content") authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) if err != nil { t.Fatal("Cannot authenticate") @@ -738,19 +644,24 @@ func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler objectName := "test.file" bucketName := getRandomBucketName() - test := func(token string) int { + test := func(token string, sendContentLength bool) int { rec := httptest.NewRecorder() - var req *http.Request - req, err = http.NewRequest("PUT", "/minio/upload/"+bucketName+"/"+objectName, nil) - if err != nil { - t.Fatalf("Cannot create upload request, %v", err) + req, rErr := http.NewRequest("PUT", "/minio/upload/"+bucketName+"/"+objectName, nil) + if rErr != nil { + t.Fatalf("Cannot create upload request, %v", rErr) } - req.Header.Set("Content-Length", strconv.Itoa(len(content))) req.Header.Set("x-amz-date", "20160814T114029Z") req.Header.Set("Accept", "*/*") + req.Body = ioutil.NopCloser(bytes.NewReader(content)) + if !sendContentLength { + req.ContentLength = -1 + } else { + req.ContentLength = int64(len(content)) + } + if token != "" { req.Header.Set("Authorization", "Bearer "+authorization) } @@ -765,7 +676,7 @@ func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler } // Authenticated upload should succeed. - code := test(authorization) + code := test(authorization, true) if code != http.StatusOK { t.Fatalf("Expected the response status to be 200, but instead found `%d`", code) } @@ -780,8 +691,14 @@ func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler t.Fatalf("The upload file is different from the download file") } + // Authenticated upload without content-length should fail + code = test(authorization, false) + if code != http.StatusBadRequest { + t.Fatalf("Expected the response status to be 200, but instead found `%d`", code) + } + // Unauthenticated upload should fail. - code = test("") + code = test("", true) if code != http.StatusForbidden { t.Fatalf("Expected the response status to be 403, but instead found `%d`", code) } @@ -794,13 +711,13 @@ func testUploadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler globalBucketPolicies.SetBucketPolicy(bucketName, policyChange{false, &policy}) // Unauthenticated upload with WRITE policy should succeed. - code = test("") + code = test("", true) if code != http.StatusOK { t.Fatalf("Expected the response status to be 200, but instead found `%d`", code) } } -// Wrapper for calling Upload Handler +// Wrapper for calling Download Handler func TestWebHandlerDownload(t *testing.T) { ExecObjectLayerTest(t, testDownloadWebHandler) } @@ -809,15 +726,6 @@ func TestWebHandlerDownload(t *testing.T) { func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -893,6 +801,89 @@ func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandl } } +// Test web.DownloadZip +func TestWebHandlerDownloadZip(t *testing.T) { + ExecObjectLayerTest(t, testWebHandlerDownloadZip) +} + +func testWebHandlerDownloadZip(obj ObjectLayer, instanceType string, t TestErrHandler) { + apiRouter := initTestWebRPCEndPoint(obj) + credentials := serverConfig.GetCredential() + + authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) + if err != nil { + t.Fatal("Cannot authenticate") + } + + bucket := getRandomBucketName() + fileOne := "aaaaaaaaaaaaaa" + fileTwo := "bbbbbbbbbbbbbb" + fileThree := "cccccccccccccc" + + // Create bucket. + err = obj.MakeBucket(bucket) + if err != nil { + // failed to create newbucket, abort. + t.Fatalf("%s : %s", instanceType, err) + } + + obj.PutObject(bucket, "a/one", int64(len(fileOne)), strings.NewReader(fileOne), nil, "") + obj.PutObject(bucket, "a/b/two", int64(len(fileTwo)), strings.NewReader(fileTwo), nil, "") + obj.PutObject(bucket, "a/c/three", int64(len(fileThree)), strings.NewReader(fileThree), nil, "") + + test := func(token string) (int, []byte) { + rec := httptest.NewRecorder() + path := "/minio/zip" + "?token=" + if token != "" { + path = path + token + } + args := DownloadZipArgs{ + Objects: []string{"one", "b/", "c/"}, + Prefix: "a/", + BucketName: bucket, + } + + var argsData []byte + argsData, err = json.Marshal(args) + if err != nil { + return 0, nil + } + var req *http.Request + req, err = http.NewRequest("GET", path, bytes.NewBuffer(argsData)) + + if err != nil { + t.Fatalf("Cannot create upload request, %v", err) + } + + apiRouter.ServeHTTP(rec, req) + return rec.Code, rec.Body.Bytes() + } + code, data := test("") + if code != 403 { + t.Fatal("Expected to receive authentication error") + } + code, data = test(authorization) + if code != 200 { + t.Fatal("web.DownloadsZip() failed") + } + reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + t.Fatal(err) + } + h := md5.New() + for _, file := range reader.File { + fileReader, err := file.Open() + if err != nil { + t.Fatal(err) + } + io.Copy(h, fileReader) + } + // Verify the md5 of the response. + if hex.EncodeToString(h.Sum(nil)) != "ac7196449b14bea42775d29e8bb29f50" { + t.Fatal("Incorrect zip contents") + } +} + // Wrapper for calling PresignedGet handler func TestWebHandlerPresignedGetHandler(t *testing.T) { ExecObjectLayerTest(t, testWebPresignedGetHandler) @@ -901,15 +892,6 @@ func TestWebHandlerPresignedGetHandler(t *testing.T) { func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -1014,15 +996,6 @@ func TestWebHandlerGetBucketPolicyHandler(t *testing.T) { func testWebGetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -1097,15 +1070,6 @@ func TestWebHandlerListAllBucketPoliciesHandler(t *testing.T) { func testWebListAllBucketPoliciesHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -1203,15 +1167,6 @@ func TestWebHandlerSetBucketPolicyHandler(t *testing.T) { func testWebSetBucketPolicyHandler(obj ObjectLayer, instanceType string, t TestErrHandler) { // Register the API end points with XL/FS object layer. apiRouter := initTestWebRPCEndPoint(obj) - // initialize the server and obtain the credentials and root. - // credentials are necessary to sign the HTTP request. - rootPath, err := newTestConfig(globalMinioDefaultRegion) - if err != nil { - t.Fatalf("Init Test config failed") - } - // remove the root directory after the test ends. - defer removeAll(rootPath) - credentials := serverConfig.GetCredential() authorization, err := getWebRPCToken(apiRouter, credentials.AccessKey, credentials.SecretKey) @@ -1533,10 +1488,6 @@ func TestWebObjectLayerFaultyDisks(t *testing.T) { if rec.Code != http.StatusOK { t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) } - resp := string(rec.Body.Bytes()) - if !strings.Contains(resp, "We encountered an internal error, please try again.") { - t.Fatalf("Unexpected error message, expected: `Invalid token`, found: `%s`", resp) - } // Test authorization of Web.Upload content := []byte("temporary file's content") @@ -1553,8 +1504,4 @@ func TestWebObjectLayerFaultyDisks(t *testing.T) { if rec.Code != http.StatusOK { t.Fatalf("Expected the response status to be 200, but instead found `%d`", rec.Code) } - resp = string(rec.Body.Bytes()) - if !strings.Contains(resp, "We encountered an internal error, please try again.") { - t.Fatalf("Unexpected error message, expected: `Invalid token`, found: `%s`", resp) - } } diff --git a/cmd/web-router.go b/cmd/web-router.go index f478abfb8..c4fdfbb2c 100644 --- a/cmd/web-router.go +++ b/cmd/web-router.go @@ -84,6 +84,7 @@ func registerWebRouter(mux *router.Router) error { webBrowserRouter.Methods("POST").Path("/webrpc").Handler(webRPC) webBrowserRouter.Methods("PUT").Path("/upload/{bucket}/{object:.+}").HandlerFunc(web.Upload) webBrowserRouter.Methods("GET").Path("/download/{bucket}/{object:.+}").Queries("token", "{token:.*}").HandlerFunc(web.Download) + webBrowserRouter.Methods("GET").Path("/zip").Queries("token", "{token:.*}").HandlerFunc(web.DownloadZip) // Add compression for assets. compressedAssets := handlers.CompressHandler(http.StripPrefix(reservedBucket, http.FileServer(assetFS()))) diff --git a/cmd/xl-v1-bucket.go b/cmd/xl-v1-bucket.go index 52e993dcf..4078b7292 100644 --- a/cmd/xl-v1-bucket.go +++ b/cmd/xl-v1-bucket.go @@ -62,18 +62,12 @@ func (xl xlObjects) MakeBucket(bucket string) error { // Wait for all make vol to finish. wg.Wait() - // Do we have write quorum?. - if !isDiskQuorum(dErrs, xl.writeQuorum) { + err := reduceWriteQuorumErrs(dErrs, bucketOpIgnoredErrs, xl.writeQuorum) + if errorCause(err) == errXLWriteQuorum { // Purge successfully created buckets if we don't have writeQuorum. undoMakeBucket(xl.storageDisks, bucket) - return toObjectErr(traceError(errXLWriteQuorum), bucket) } - - // Verify we have any other errors which should undo make bucket. - if reducedErr := reduceWriteQuorumErrs(dErrs, bucketOpIgnoredErrs, xl.writeQuorum); reducedErr != nil { - return toObjectErr(reducedErr, bucket) - } - return nil + return toObjectErr(err, bucket) } func (xl xlObjects) undoDeleteBucket(bucket string) { @@ -253,15 +247,9 @@ func (xl xlObjects) DeleteBucket(bucket string) error { // Wait for all the delete vols to finish. wg.Wait() - if !isDiskQuorum(dErrs, xl.writeQuorum) { + err := reduceWriteQuorumErrs(dErrs, bucketOpIgnoredErrs, xl.writeQuorum) + if errorCause(err) == errXLWriteQuorum { xl.undoDeleteBucket(bucket) - return toObjectErr(traceError(errXLWriteQuorum), bucket) } - - if reducedErr := reduceWriteQuorumErrs(dErrs, bucketOpIgnoredErrs, xl.writeQuorum); reducedErr != nil { - return toObjectErr(reducedErr, bucket) - } - - // Success. - return nil + return toObjectErr(err, bucket) } diff --git a/cmd/xl-v1-healing.go b/cmd/xl-v1-healing.go index 49a03676b..d0aaf56a7 100644 --- a/cmd/xl-v1-healing.go +++ b/cmd/xl-v1-healing.go @@ -109,18 +109,12 @@ func healBucket(storageDisks []StorageAPI, bucket string, writeQuorum int) error // Wait for all make vol to finish. wg.Wait() - // Do we have write quorum?. - if !isDiskQuorum(dErrs, writeQuorum) { + reducedErr := reduceWriteQuorumErrs(dErrs, bucketOpIgnoredErrs, writeQuorum) + if errorCause(reducedErr) == errXLWriteQuorum { // Purge successfully created buckets if we don't have writeQuorum. undoMakeBucket(storageDisks, bucket) - return toObjectErr(traceError(errXLWriteQuorum), bucket) } - - // Verify we have any other errors which should be returned as failure. - if reducedErr := reduceWriteQuorumErrs(dErrs, bucketOpIgnoredErrs, writeQuorum); reducedErr != nil { - return toObjectErr(reducedErr, bucket) - } - return nil + return reducedErr } // Heals all the metadata associated for a given bucket, this function @@ -344,22 +338,34 @@ func healObject(storageDisks []StorageAPI, bucket string, object string, quorum // Not an outdated disk. continue } - if errs[index] != nil { - // If there was an error (most likely errFileNotFound) + + // errFileNotFound implies that xl.json is missing. We + // may have object parts still present in the object + // directory. This needs to be deleted for object to + // healed successfully. + if errs[index] != nil && !isErr(errs[index], errFileNotFound) { continue } + // Outdated object with the same name exists that needs to be deleted. outDatedMeta := partsMetadata[index] - // Delete all the parts. - for partIndex := 0; partIndex < len(outDatedMeta.Parts); partIndex++ { - err := disk.DeleteFile(bucket, pathJoin(object, outDatedMeta.Parts[partIndex].Name)) - if err != nil { + // Consult valid metadata picked when there is no + // metadata available on this disk. + if isErr(errs[index], errFileNotFound) { + outDatedMeta = latestMeta + } + + // Delete all the parts. Ignore if parts are not found. + for _, part := range outDatedMeta.Parts { + err := disk.DeleteFile(bucket, pathJoin(object, part.Name)) + if err != nil && !isErr(err, errFileNotFound) { return traceError(err) } } - // Delete xl.json file. + + // Delete xl.json file. Ignore if xl.json not found. err := disk.DeleteFile(bucket, pathJoin(object, xlMetaJSONFile)) - if err != nil { + if err != nil && !isErr(err, errFileNotFound) { return traceError(err) } } diff --git a/cmd/xl-v1-list-objects-heal_test.go b/cmd/xl-v1-list-objects-heal_test.go index e21ab7765..fb515e325 100644 --- a/cmd/xl-v1-list-objects-heal_test.go +++ b/cmd/xl-v1-list-objects-heal_test.go @@ -25,6 +25,8 @@ import ( // TestListObjectsHeal - Tests ListObjectsHeal API for XL func TestListObjectsHeal(t *testing.T) { + initNSLock(false) + rootPath, err := newTestConfig(globalMinioDefaultRegion) if err != nil { t.Fatalf("Init Test config failed") @@ -49,15 +51,15 @@ func TestListObjectsHeal(t *testing.T) { t.Fatal(err) } - // Put 500 objects under sane dir - for i := 0; i < 500; i++ { + // Put 5 objects under sane dir + for i := 0; i < 5; i++ { _, err = xl.PutObject(bucketName, "sane/"+objName+strconv.Itoa(i), int64(len("abcd")), bytes.NewReader([]byte("abcd")), nil, "") if err != nil { t.Fatalf("XL Object upload failed: %s", err) } } // Put 500 objects under unsane/subdir dir - for i := 0; i < 500; i++ { + for i := 0; i < 5; i++ { _, err = xl.PutObject(bucketName, "unsane/subdir/"+objName+strconv.Itoa(i), int64(len("abcd")), bytes.NewReader([]byte("abcd")), nil, "") if err != nil { t.Fatalf("XL Object upload failed: %s", err) @@ -106,7 +108,7 @@ func TestListObjectsHeal(t *testing.T) { // Test ListObjectsHeal when all objects under unsane need healing xlObj := xl.(*xlObjects) - for i := 0; i < 500; i++ { + for i := 0; i < 5; i++ { if err = xlObj.storageDisks[0].DeleteFile(bucketName, "unsane/subdir/"+objName+strconv.Itoa(i)+"/xl.json"); err != nil { t.Fatal(err) } @@ -116,21 +118,21 @@ func TestListObjectsHeal(t *testing.T) { testCases = []testData{ // Test ListObjectsHeal when all objects under unsane/ need to be healed - {bucketName, "", "", "", 1000, nil, 500}, + {bucketName, "", "", "", 1000, nil, 5}, // List objects heal under unsane/, should return all elements - {bucketName, "unsane/", "", "", 1000, nil, 500}, + {bucketName, "unsane/", "", "", 1000, nil, 5}, // List healing objects under sane/, should return 0 {bucketName, "sane/", "", "", 1000, nil, 0}, // Max Keys == 200 - {bucketName, "unsane/", "", "", 200, nil, 200}, + {bucketName, "unsane/", "", "", 2, nil, 2}, // Max key > 1000 - {bucketName, "unsane/", "", "", 5000, nil, 500}, + {bucketName, "unsane/", "", "", 5000, nil, 5}, // Prefix == Delimiter == "/" - {bucketName, "/", "", "/", 5000, nil, 0}, + {bucketName, "/", "", "/", 1000, nil, 0}, // Max Keys == 0 {bucketName, "", "", "", 0, nil, 0}, // Testing with marker parameter - {bucketName, "", "unsane/subdir/" + objName + "0", "", 1000, nil, 499}, + {bucketName, "", "unsane/subdir/" + objName + "0", "", 1000, nil, 4}, } for i, testCase := range testCases { testFunc(testCase, i+1) diff --git a/cmd/xl-v1-list-objects.go b/cmd/xl-v1-list-objects.go index 477c25768..b9fff36ee 100644 --- a/cmd/xl-v1-list-objects.go +++ b/cmd/xl-v1-list-objects.go @@ -18,6 +18,34 @@ package cmd import "strings" +// Returns function "listDir" of the type listDirFunc. +// isLeaf - is used by listDir function to check if an entry is a leaf or non-leaf entry. +// disks - used for doing disk.ListDir(). FS passes single disk argument, XL passes a list of disks. +func listDirFactory(isLeaf isLeafFunc, treeWalkIgnoredErrs []error, disks ...StorageAPI) listDirFunc { + // listDir - lists all the entries at a given prefix and given entry in the prefix. + listDir := func(bucket, prefixDir, prefixEntry string) (entries []string, delayIsLeaf bool, err error) { + for _, disk := range disks { + if disk == nil { + continue + } + entries, err = disk.ListDir(bucket, prefixDir) + if err == nil { + entries, delayIsLeaf = filterListEntries(bucket, prefixDir, entries, prefixEntry, isLeaf) + return entries, delayIsLeaf, nil + } + // For any reason disk was deleted or goes offline, continue + // and list from other disks if possible. + if isErrIgnored(err, treeWalkIgnoredErrs...) { + continue + } + break + } + // Return error at the end. + return nil, false, traceError(err) + } + return listDir +} + // listObjects - wrapper function implemented over file tree walk. func (xl xlObjects) listObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, error) { // Default is recursive, if delimiter is set then list non recursive. diff --git a/cmd/xl-v1-metadata.go b/cmd/xl-v1-metadata.go index 05149c48e..243dab9fe 100644 --- a/cmd/xl-v1-metadata.go +++ b/cmd/xl-v1-metadata.go @@ -368,13 +368,12 @@ func writeUniqueXLMetadata(disks []StorageAPI, bucket, prefix string, xlMetas [] // Wait for all the routines. wg.Wait() - // Do we have write quorum?. - if !isDiskQuorum(mErrs, quorum) { + err := reduceWriteQuorumErrs(mErrs, objectOpIgnoredErrs, quorum) + if errorCause(err) == errXLWriteQuorum { // Delete all `xl.json` successfully renamed. deleteAllXLMetadata(disks, bucket, prefix, mErrs) - return traceError(errXLWriteQuorum) } - return reduceWriteQuorumErrs(mErrs, objectOpIgnoredErrs, quorum) + return err } // writeSameXLMetadata - write `xl.json` on all disks in order. @@ -407,11 +406,10 @@ func writeSameXLMetadata(disks []StorageAPI, bucket, prefix string, xlMeta xlMet // Wait for all the routines. wg.Wait() - // Do we have write Quorum?. - if !isDiskQuorum(mErrs, writeQuorum) { + err := reduceWriteQuorumErrs(mErrs, objectOpIgnoredErrs, writeQuorum) + if errorCause(err) == errXLWriteQuorum { // Delete all `xl.json` successfully renamed. deleteAllXLMetadata(disks, bucket, prefix, mErrs) - return traceError(errXLWriteQuorum) } - return reduceWriteQuorumErrs(mErrs, objectOpIgnoredErrs, writeQuorum) + return err } diff --git a/cmd/xl-v1-multipart-common.go b/cmd/xl-v1-multipart-common.go deleted file mode 100644 index 1734c88b0..000000000 --- a/cmd/xl-v1-multipart-common.go +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package cmd - -import ( - "path" - "sync" - "time" -) - -// updateUploadJSON - add or remove upload ID info in all `uploads.json`. -func (xl xlObjects) updateUploadJSON(bucket, object, uploadID string, initiated time.Time, isRemove bool) error { - uploadsPath := path.Join(bucket, object, uploadsJSONFile) - tmpUploadsPath := mustGetUUID() - - // slice to store errors from disks - errs := make([]error, len(xl.storageDisks)) - // slice to store if it is a delete operation on a disk - isDelete := make([]bool, len(xl.storageDisks)) - - wg := sync.WaitGroup{} - for index, disk := range xl.storageDisks { - if disk == nil { - errs[index] = traceError(errDiskNotFound) - continue - } - // Update `uploads.json` in a go routine. - wg.Add(1) - go func(index int, disk StorageAPI) { - defer wg.Done() - - // read and parse uploads.json on this disk - uploadsJSON, err := readUploadsJSON(bucket, object, disk) - if errorCause(err) == errFileNotFound { - // If file is not found, we assume an - // default (empty) upload info. - uploadsJSON, err = newUploadsV1("xl"), nil - } - // If we have a read error, we store error and - // exit. - if err != nil { - errs[index] = err - return - } - - if !isRemove { - // Add the uploadID - uploadsJSON.AddUploadID(uploadID, initiated) - } else { - // Remove the upload ID - uploadsJSON.RemoveUploadID(uploadID) - if len(uploadsJSON.Uploads) == 0 { - isDelete[index] = true - } - } - - // For delete, rename to tmp, for the - // possibility of recovery in case of quorum - // failure. - if !isDelete[index] { - errs[index] = writeUploadJSON(&uploadsJSON, uploadsPath, tmpUploadsPath, disk) - } else { - wErr := disk.RenameFile(minioMetaMultipartBucket, uploadsPath, minioMetaTmpBucket, tmpUploadsPath) - if wErr != nil { - errs[index] = traceError(wErr) - } - - } - }(index, disk) - } - - // Wait for all the writes to finish. - wg.Wait() - - // Do we have write quorum? - if !isDiskQuorum(errs, xl.writeQuorum) { - // No quorum. Perform cleanup on the minority of disks - // on which the operation succeeded. - - // There are two cases: - // - // 1. uploads.json file was updated -> we delete the - // file that we successfully overwrote on the - // minority of disks, so that the failed quorum - // operation is not partially visible. - // - // 2. uploads.json was deleted -> in this case since - // the delete failed, we restore from tmp. - for index, disk := range xl.storageDisks { - if disk == nil || errs[index] != nil { - continue - } - wg.Add(1) - go func(index int, disk StorageAPI) { - defer wg.Done() - if !isDelete[index] { - _ = disk.DeleteFile( - minioMetaMultipartBucket, - uploadsPath, - ) - } else { - _ = disk.RenameFile( - minioMetaTmpBucket, tmpUploadsPath, - minioMetaMultipartBucket, uploadsPath, - ) - } - }(index, disk) - } - wg.Wait() - return traceError(errXLWriteQuorum) - } - - // we do have quorum, so in case of delete upload.json file - // operation, we purge from tmp. - for index, disk := range xl.storageDisks { - if disk == nil || !isDelete[index] { - continue - } - wg.Add(1) - go func(index int, disk StorageAPI) { - defer wg.Done() - // isDelete[index] = true at this point. - _ = disk.DeleteFile(minioMetaTmpBucket, tmpUploadsPath) - }(index, disk) - } - wg.Wait() - - if reducedErr := reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, xl.writeQuorum); reducedErr != nil { - return reducedErr - } - return nil -} - -// addUploadID - add upload ID and its initiated time to 'uploads.json'. -func (xl xlObjects) addUploadID(bucket, object string, uploadID string, initiated time.Time) error { - return xl.updateUploadJSON(bucket, object, uploadID, initiated, false) -} - -// removeUploadID - remove upload ID in 'uploads.json'. -func (xl xlObjects) removeUploadID(bucket, object string, uploadID string) error { - return xl.updateUploadJSON(bucket, object, uploadID, time.Time{}, true) -} - -// Returns if the prefix is a multipart upload. -func (xl xlObjects) isMultipartUpload(bucket, prefix string) bool { - for _, disk := range xl.getLoadBalancedDisks() { - if disk == nil { - continue - } - _, err := disk.StatFile(bucket, pathJoin(prefix, uploadsJSONFile)) - if err == nil { - return true - } - // For any reason disk was deleted or goes offline, continue - if isErrIgnored(err, objMetadataOpIgnoredErrs...) { - continue - } - break - } - return false -} - -// isUploadIDExists - verify if a given uploadID exists and is valid. -func (xl xlObjects) isUploadIDExists(bucket, object, uploadID string) bool { - uploadIDPath := path.Join(bucket, object, uploadID) - return xl.isObject(minioMetaMultipartBucket, uploadIDPath) -} - -// Removes part given by partName belonging to a mulitpart upload from minioMetaBucket -func (xl xlObjects) removeObjectPart(bucket, object, uploadID, partName string) { - curpartPath := path.Join(bucket, object, uploadID, partName) - wg := sync.WaitGroup{} - for i, disk := range xl.storageDisks { - if disk == nil { - continue - } - wg.Add(1) - go func(index int, disk StorageAPI) { - defer wg.Done() - // Ignoring failure to remove parts that weren't present in CompleteMultipartUpload - // requests. xl.json is the authoritative source of truth on which parts constitute - // the object. The presence of parts that don't belong in the object doesn't affect correctness. - _ = disk.DeleteFile(minioMetaMultipartBucket, curpartPath) - }(i, disk) - } - wg.Wait() -} - -// statPart - returns fileInfo structure for a successful stat on part file. -func (xl xlObjects) statPart(bucket, object, uploadID, partName string) (fileInfo FileInfo, err error) { - partNamePath := path.Join(bucket, object, uploadID, partName) - for _, disk := range xl.getLoadBalancedDisks() { - if disk == nil { - continue - } - fileInfo, err = disk.StatFile(minioMetaMultipartBucket, partNamePath) - if err == nil { - return fileInfo, nil - } - err = traceError(err) - // For any reason disk was deleted or goes offline we continue to next disk. - if isErrIgnored(err, objMetadataOpIgnoredErrs...) { - continue - } - - // Catastrophic error, we return. - break - } - return FileInfo{}, err -} - -// commitXLMetadata - commit `xl.json` from source prefix to destination prefix in the given slice of disks. -func commitXLMetadata(disks []StorageAPI, srcBucket, srcPrefix, dstBucket, dstPrefix string, quorum int) error { - var wg = &sync.WaitGroup{} - var mErrs = make([]error, len(disks)) - - srcJSONFile := path.Join(srcPrefix, xlMetaJSONFile) - dstJSONFile := path.Join(dstPrefix, xlMetaJSONFile) - - // Rename `xl.json` to all disks in parallel. - for index, disk := range disks { - if disk == nil { - mErrs[index] = traceError(errDiskNotFound) - continue - } - wg.Add(1) - // Rename `xl.json` in a routine. - go func(index int, disk StorageAPI) { - defer wg.Done() - // Delete any dangling directories. - defer disk.DeleteFile(srcBucket, srcPrefix) - - // Renames `xl.json` from source prefix to destination prefix. - rErr := disk.RenameFile(srcBucket, srcJSONFile, dstBucket, dstJSONFile) - if rErr != nil { - mErrs[index] = traceError(rErr) - return - } - mErrs[index] = nil - }(index, disk) - } - // Wait for all the routines. - wg.Wait() - - // Do we have write Quorum?. - if !isDiskQuorum(mErrs, quorum) { - // Delete all `xl.json` successfully renamed. - deleteAllXLMetadata(disks, dstBucket, dstPrefix, mErrs) - return traceError(errXLWriteQuorum) - } - - if reducedErr := reduceWriteQuorumErrs(mErrs, objectOpIgnoredErrs, quorum); reducedErr != nil { - return reducedErr - } - return nil -} diff --git a/cmd/xl-v1-multipart.go b/cmd/xl-v1-multipart.go index 58f421121..51624784c 100644 --- a/cmd/xl-v1-multipart.go +++ b/cmd/xl-v1-multipart.go @@ -25,12 +25,251 @@ import ( "io/ioutil" "path" "strings" + "sync" "time" "github.com/minio/minio/pkg/mimedb" "github.com/minio/sha256-simd" ) +// updateUploadJSON - add or remove upload ID info in all `uploads.json`. +func (xl xlObjects) updateUploadJSON(bucket, object, uploadID string, initiated time.Time, isRemove bool) error { + uploadsPath := path.Join(bucket, object, uploadsJSONFile) + tmpUploadsPath := mustGetUUID() + + // slice to store errors from disks + errs := make([]error, len(xl.storageDisks)) + // slice to store if it is a delete operation on a disk + isDelete := make([]bool, len(xl.storageDisks)) + + wg := sync.WaitGroup{} + for index, disk := range xl.storageDisks { + if disk == nil { + errs[index] = traceError(errDiskNotFound) + continue + } + // Update `uploads.json` in a go routine. + wg.Add(1) + go func(index int, disk StorageAPI) { + defer wg.Done() + + // read and parse uploads.json on this disk + uploadsJSON, err := readUploadsJSON(bucket, object, disk) + if errorCause(err) == errFileNotFound { + // If file is not found, we assume an + // default (empty) upload info. + uploadsJSON, err = newUploadsV1("xl"), nil + } + // If we have a read error, we store error and + // exit. + if err != nil { + errs[index] = err + return + } + + if !isRemove { + // Add the uploadID + uploadsJSON.AddUploadID(uploadID, initiated) + } else { + // Remove the upload ID + uploadsJSON.RemoveUploadID(uploadID) + if len(uploadsJSON.Uploads) == 0 { + isDelete[index] = true + } + } + + // For delete, rename to tmp, for the + // possibility of recovery in case of quorum + // failure. + if !isDelete[index] { + errs[index] = writeUploadJSON(&uploadsJSON, uploadsPath, tmpUploadsPath, disk) + } else { + wErr := disk.RenameFile(minioMetaMultipartBucket, uploadsPath, minioMetaTmpBucket, tmpUploadsPath) + if wErr != nil { + errs[index] = traceError(wErr) + } + + } + }(index, disk) + } + + // Wait for all the writes to finish. + wg.Wait() + + err := reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, xl.writeQuorum) + if errorCause(err) == errXLWriteQuorum { + // No quorum. Perform cleanup on the minority of disks + // on which the operation succeeded. + + // There are two cases: + // + // 1. uploads.json file was updated -> we delete the + // file that we successfully overwrote on the + // minority of disks, so that the failed quorum + // operation is not partially visible. + // + // 2. uploads.json was deleted -> in this case since + // the delete failed, we restore from tmp. + for index, disk := range xl.storageDisks { + if disk == nil || errs[index] != nil { + continue + } + wg.Add(1) + go func(index int, disk StorageAPI) { + defer wg.Done() + if !isDelete[index] { + _ = disk.DeleteFile( + minioMetaMultipartBucket, + uploadsPath, + ) + } else { + _ = disk.RenameFile( + minioMetaTmpBucket, tmpUploadsPath, + minioMetaMultipartBucket, uploadsPath, + ) + } + }(index, disk) + } + wg.Wait() + return err + } + + // we do have quorum, so in case of delete upload.json file + // operation, we purge from tmp. + for index, disk := range xl.storageDisks { + if disk == nil || !isDelete[index] { + continue + } + wg.Add(1) + go func(index int, disk StorageAPI) { + defer wg.Done() + // isDelete[index] = true at this point. + _ = disk.DeleteFile(minioMetaTmpBucket, tmpUploadsPath) + }(index, disk) + } + wg.Wait() + return err +} + +// addUploadID - add upload ID and its initiated time to 'uploads.json'. +func (xl xlObjects) addUploadID(bucket, object string, uploadID string, initiated time.Time) error { + return xl.updateUploadJSON(bucket, object, uploadID, initiated, false) +} + +// removeUploadID - remove upload ID in 'uploads.json'. +func (xl xlObjects) removeUploadID(bucket, object string, uploadID string) error { + return xl.updateUploadJSON(bucket, object, uploadID, time.Time{}, true) +} + +// Returns if the prefix is a multipart upload. +func (xl xlObjects) isMultipartUpload(bucket, prefix string) bool { + for _, disk := range xl.getLoadBalancedDisks() { + if disk == nil { + continue + } + _, err := disk.StatFile(bucket, pathJoin(prefix, uploadsJSONFile)) + if err == nil { + return true + } + // For any reason disk was deleted or goes offline, continue + if isErrIgnored(err, objMetadataOpIgnoredErrs...) { + continue + } + break + } + return false +} + +// isUploadIDExists - verify if a given uploadID exists and is valid. +func (xl xlObjects) isUploadIDExists(bucket, object, uploadID string) bool { + uploadIDPath := path.Join(bucket, object, uploadID) + return xl.isObject(minioMetaMultipartBucket, uploadIDPath) +} + +// Removes part given by partName belonging to a mulitpart upload from minioMetaBucket +func (xl xlObjects) removeObjectPart(bucket, object, uploadID, partName string) { + curpartPath := path.Join(bucket, object, uploadID, partName) + wg := sync.WaitGroup{} + for i, disk := range xl.storageDisks { + if disk == nil { + continue + } + wg.Add(1) + go func(index int, disk StorageAPI) { + defer wg.Done() + // Ignoring failure to remove parts that weren't present in CompleteMultipartUpload + // requests. xl.json is the authoritative source of truth on which parts constitute + // the object. The presence of parts that don't belong in the object doesn't affect correctness. + _ = disk.DeleteFile(minioMetaMultipartBucket, curpartPath) + }(i, disk) + } + wg.Wait() +} + +// statPart - returns fileInfo structure for a successful stat on part file. +func (xl xlObjects) statPart(bucket, object, uploadID, partName string) (fileInfo FileInfo, err error) { + partNamePath := path.Join(bucket, object, uploadID, partName) + for _, disk := range xl.getLoadBalancedDisks() { + if disk == nil { + continue + } + fileInfo, err = disk.StatFile(minioMetaMultipartBucket, partNamePath) + if err == nil { + return fileInfo, nil + } + err = traceError(err) + // For any reason disk was deleted or goes offline we continue to next disk. + if isErrIgnored(err, objMetadataOpIgnoredErrs...) { + continue + } + + // Catastrophic error, we return. + break + } + return FileInfo{}, err +} + +// commitXLMetadata - commit `xl.json` from source prefix to destination prefix in the given slice of disks. +func commitXLMetadata(disks []StorageAPI, srcBucket, srcPrefix, dstBucket, dstPrefix string, quorum int) error { + var wg = &sync.WaitGroup{} + var mErrs = make([]error, len(disks)) + + srcJSONFile := path.Join(srcPrefix, xlMetaJSONFile) + dstJSONFile := path.Join(dstPrefix, xlMetaJSONFile) + + // Rename `xl.json` to all disks in parallel. + for index, disk := range disks { + if disk == nil { + mErrs[index] = traceError(errDiskNotFound) + continue + } + wg.Add(1) + // Rename `xl.json` in a routine. + go func(index int, disk StorageAPI) { + defer wg.Done() + // Delete any dangling directories. + defer disk.DeleteFile(srcBucket, srcPrefix) + + // Renames `xl.json` from source prefix to destination prefix. + rErr := disk.RenameFile(srcBucket, srcJSONFile, dstBucket, dstJSONFile) + if rErr != nil { + mErrs[index] = traceError(rErr) + return + } + mErrs[index] = nil + }(index, disk) + } + // Wait for all the routines. + wg.Wait() + + err := reduceWriteQuorumErrs(mErrs, objectOpIgnoredErrs, quorum) + if errorCause(err) == errXLWriteQuorum { + // Delete all `xl.json` successfully renamed. + deleteAllXLMetadata(disks, dstBucket, dstPrefix, mErrs) + } + return err +} + // listMultipartUploads - lists all multipart uploads. func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (ListMultipartsInfo, error) { result := ListMultipartsInfo{ @@ -251,7 +490,8 @@ func (xl xlObjects) newMultipartUpload(bucket string, object string, meta map[st uploadIDPath := path.Join(bucket, object, uploadID) tempUploadIDPath := uploadID // Write updated `xl.json` to all disks. - if err := writeSameXLMetadata(xl.storageDisks, minioMetaTmpBucket, tempUploadIDPath, xlMeta, xl.writeQuorum, xl.readQuorum); err != nil { + err := writeSameXLMetadata(xl.storageDisks, minioMetaTmpBucket, tempUploadIDPath, xlMeta, xl.writeQuorum, xl.readQuorum) + if err != nil { return "", toObjectErr(err, minioMetaTmpBucket, tempUploadIDPath) } // delete the tmp path later in case we fail to rename (ignore @@ -290,14 +530,49 @@ func (xl xlObjects) NewMultipartUpload(bucket, object string, meta map[string]st return xl.newMultipartUpload(bucket, object, meta) } +// CopyObjectPart - reads incoming stream and internally erasure codes +// them. This call is similar to put object part operation but the source +// data is read from an existing object. +// +// Implements S3 compatible Upload Part Copy API. +func (xl xlObjects) CopyObjectPart(srcBucket, srcObject, dstBucket, dstObject, uploadID string, partID int, startOffset int64, length int64) (PartInfo, error) { + if err := checkNewMultipartArgs(srcBucket, srcObject, xl); err != nil { + return PartInfo{}, err + } + + // Initialize pipe. + pipeReader, pipeWriter := io.Pipe() + + go func() { + startOffset := int64(0) // Read the whole file. + if gerr := xl.GetObject(srcBucket, srcObject, startOffset, length, pipeWriter); gerr != nil { + errorIf(gerr, "Unable to read %s of the object `%s/%s`.", srcBucket, srcObject) + pipeWriter.CloseWithError(toObjectErr(gerr, srcBucket, srcObject)) + return + } + pipeWriter.Close() // Close writer explicitly signalling we wrote all data. + }() + + partInfo, err := xl.PutObjectPart(dstBucket, dstObject, uploadID, partID, length, pipeReader, "", "") + if err != nil { + return PartInfo{}, toObjectErr(err, dstBucket, dstObject) + } + + // Explicitly close the reader. + pipeReader.Close() + + // Success. + return partInfo, nil +} + // PutObjectPart - reads incoming stream and internally erasure codes // them. This call is similar to single put operation but it is part // of the multipart transaction. // // Implements S3 compatible Upload Part API. -func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (string, error) { +func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, size int64, data io.Reader, md5Hex string, sha256sum string) (PartInfo, error) { if err := checkPutObjectPartArgs(bucket, object, xl); err != nil { - return "", err + return PartInfo{}, err } var partsMetadata []xlMetaV1 @@ -310,14 +585,16 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s // Validates if upload ID exists. if !xl.isUploadIDExists(bucket, object, uploadID) { preUploadIDLock.RUnlock() - return "", traceError(InvalidUploadID{UploadID: uploadID}) + return PartInfo{}, traceError(InvalidUploadID{UploadID: uploadID}) } + // Read metadata associated with the object from all disks. partsMetadata, errs = readAllXLMetadata(xl.storageDisks, minioMetaMultipartBucket, uploadIDPath) - if !isDiskQuorum(errs, xl.writeQuorum) { + reducedErr := reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, xl.writeQuorum) + if errorCause(reducedErr) == errXLWriteQuorum { preUploadIDLock.RUnlock() - return "", toObjectErr(traceError(errXLWriteQuorum), bucket, object) + return PartInfo{}, toObjectErr(reducedErr, bucket, object) } preUploadIDLock.RUnlock() @@ -327,7 +604,7 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s // Pick one from the first valid metadata. xlMeta, err := pickValidXLMeta(partsMetadata, modTime) if err != nil { - return "", err + return PartInfo{}, err } onlineDisks = getOrderedDisks(xlMeta.Erasure.Distribution, onlineDisks) @@ -379,16 +656,19 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s } } + // We always allow empty part. + allowEmpty := true + // Erasure code data and write across all disks. - sizeWritten, checkSums, err := erasureCreateFile(onlineDisks, minioMetaTmpBucket, tmpPartPath, teeReader, xlMeta.Erasure.BlockSize, xl.dataBlocks, xl.parityBlocks, bitRotAlgo, xl.writeQuorum) + sizeWritten, checkSums, err := erasureCreateFile(onlineDisks, minioMetaTmpBucket, tmpPartPath, teeReader, allowEmpty, xlMeta.Erasure.BlockSize, xl.dataBlocks, xl.parityBlocks, bitRotAlgo, xl.writeQuorum) if err != nil { - return "", toObjectErr(err, bucket, object) + return PartInfo{}, toObjectErr(err, bucket, object) } // Should return IncompleteBody{} error when reader has fewer bytes // than specified in request header. if sizeWritten < size { - return "", traceError(IncompleteBody{}) + return PartInfo{}, traceError(IncompleteBody{}) } // For size == -1, perhaps client is sending in chunked encoding @@ -402,14 +682,14 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s if md5Hex != "" { if newMD5Hex != md5Hex { // Returns md5 mismatch. - return "", traceError(BadDigest{md5Hex, newMD5Hex}) + return PartInfo{}, traceError(BadDigest{md5Hex, newMD5Hex}) } } if sha256sum != "" { newSHA256sum := hex.EncodeToString(sha256Writer.Sum(nil)) if newSHA256sum != sha256sum { - return "", traceError(SHA256Mismatch{}) + return PartInfo{}, traceError(SHA256Mismatch{}) } } @@ -420,20 +700,21 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s // Validate again if upload ID still exists. if !xl.isUploadIDExists(bucket, object, uploadID) { - return "", traceError(InvalidUploadID{UploadID: uploadID}) + return PartInfo{}, traceError(InvalidUploadID{UploadID: uploadID}) } // Rename temporary part file to its final location. partPath := path.Join(uploadIDPath, partSuffix) err = renamePart(onlineDisks, minioMetaTmpBucket, tmpPartPath, minioMetaMultipartBucket, partPath, xl.writeQuorum) if err != nil { - return "", toObjectErr(err, minioMetaMultipartBucket, partPath) + return PartInfo{}, toObjectErr(err, minioMetaMultipartBucket, partPath) } // Read metadata again because it might be updated with parallel upload of another part. partsMetadata, errs = readAllXLMetadata(onlineDisks, minioMetaMultipartBucket, uploadIDPath) - if !isDiskQuorum(errs, xl.writeQuorum) { - return "", toObjectErr(traceError(errXLWriteQuorum), bucket, object) + reducedErr = reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, xl.writeQuorum) + if errorCause(reducedErr) == errXLWriteQuorum { + return PartInfo{}, toObjectErr(reducedErr, bucket, object) } // Get current highest version based on re-read partsMetadata. @@ -442,7 +723,7 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s // Pick one from the first valid metadata. xlMeta, err = pickValidXLMeta(partsMetadata, modTime) if err != nil { - return "", err + return PartInfo{}, err } // Once part is successfully committed, proceed with updating XL metadata. @@ -469,15 +750,25 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s // Writes a unique `xl.json` each disk carrying new checksum related information. if err = writeUniqueXLMetadata(onlineDisks, minioMetaTmpBucket, tempXLMetaPath, partsMetadata, xl.writeQuorum); err != nil { - return "", toObjectErr(err, minioMetaTmpBucket, tempXLMetaPath) + return PartInfo{}, toObjectErr(err, minioMetaTmpBucket, tempXLMetaPath) } rErr := commitXLMetadata(onlineDisks, minioMetaTmpBucket, tempXLMetaPath, minioMetaMultipartBucket, uploadIDPath, xl.writeQuorum) if rErr != nil { - return "", toObjectErr(rErr, minioMetaMultipartBucket, uploadIDPath) + return PartInfo{}, toObjectErr(rErr, minioMetaMultipartBucket, uploadIDPath) + } + + fi, err := xl.statPart(bucket, object, uploadID, partSuffix) + if err != nil { + return PartInfo{}, toObjectErr(rErr, minioMetaMultipartBucket, partSuffix) } // Return success. - return newMD5Hex, nil + return PartInfo{ + PartNumber: partID, + LastModified: fi.ModTime, + ETag: newMD5Hex, + Size: fi.Size, + }, nil } // listObjectParts - wrapper reading `xl.json` for a given object and @@ -521,7 +812,7 @@ func (xl xlObjects) listObjectParts(bucket, object, uploadID string, partNumberM if err != nil { return ListPartsInfo{}, toObjectErr(err, minioMetaBucket, path.Join(uploadID, part.Name)) } - result.Parts = append(result.Parts, partInfo{ + result.Parts = append(result.Parts, PartInfo{ PartNumber: part.Number, ETag: part.ETag, LastModified: fi.ModTime, @@ -604,9 +895,9 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload // Read metadata associated with the object from all disks. partsMetadata, errs := readAllXLMetadata(xl.storageDisks, minioMetaMultipartBucket, uploadIDPath) - // Do we have writeQuorum?. - if !isDiskQuorum(errs, xl.writeQuorum) { - return ObjectInfo{}, toObjectErr(traceError(errXLWriteQuorum), bucket, object) + reducedErr := reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, xl.writeQuorum) + if errorCause(reducedErr) == errXLWriteQuorum { + return ObjectInfo{}, toObjectErr(reducedErr, bucket, object) } onlineDisks, modTime := listOnlineDisks(xl.storageDisks, partsMetadata, errs) @@ -779,13 +1070,44 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload return objInfo, nil } +// Wrapper which removes all the uploaded parts. +func (xl xlObjects) cleanupUploadedParts(bucket, object, uploadID string) error { + var errs = make([]error, len(xl.storageDisks)) + var wg = &sync.WaitGroup{} + + // Construct uploadIDPath. + uploadIDPath := path.Join(bucket, object, uploadID) + + // Cleanup uploadID for all disks. + for index, disk := range xl.storageDisks { + if disk == nil { + errs[index] = traceError(errDiskNotFound) + continue + } + wg.Add(1) + // Cleanup each uploadID in a routine. + go func(index int, disk StorageAPI) { + defer wg.Done() + err := cleanupDir(disk, minioMetaMultipartBucket, uploadIDPath) + if err != nil { + errs[index] = err + } + }(index, disk) + } + + // Wait for all the cleanups to finish. + wg.Wait() + + return reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, xl.writeQuorum) +} + // abortMultipartUpload - wrapper for purging an ongoing multipart // transaction, deletes uploadID entry from `uploads.json` and purges // the directory at '.minio.sys/multipart/bucket/object/uploadID' holding // all the upload parts. func (xl xlObjects) abortMultipartUpload(bucket, object, uploadID string) (err error) { // Cleanup all uploaded parts. - if err = cleanupUploadedParts(bucket, object, uploadID, xl.storageDisks...); err != nil { + if err = xl.cleanupUploadedParts(bucket, object, uploadID); err != nil { return toObjectErr(err, bucket, object) } @@ -831,6 +1153,5 @@ func (xl xlObjects) AbortMultipartUpload(bucket, object, uploadID string) error if !xl.isUploadIDExists(bucket, object, uploadID) { return traceError(InvalidUploadID{UploadID: uploadID}) } - err := xl.abortMultipartUpload(bucket, object, uploadID) - return err + return xl.abortMultipartUpload(bucket, object, uploadID) } diff --git a/cmd/xl-v1-multipart-common_test.go b/cmd/xl-v1-multipart_test.go similarity index 100% rename from cmd/xl-v1-multipart-common_test.go rename to cmd/xl-v1-multipart_test.go diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index 2e4c632ca..1ac3f23fe 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -22,6 +22,7 @@ import ( "hash" "io" "path" + "strconv" "strings" "sync" "time" @@ -33,12 +34,7 @@ import ( ) // list all errors which can be ignored in object operations. -var objectOpIgnoredErrs = []error{ - errDiskNotFound, - errDiskAccessDenied, - errFaultyDisk, - errFaultyRemoteDisk, -} +var objectOpIgnoredErrs = append(baseIgnoredErrs, errDiskAccessDenied) /// Object Operations @@ -48,11 +44,6 @@ var objectOpIgnoredErrs = []error{ func (xl xlObjects) CopyObject(srcBucket, srcObject, dstBucket, dstObject string, metadata map[string]string) (ObjectInfo, error) { // Read metadata associated with the object from all disks. metaArr, errs := readAllXLMetadata(xl.storageDisks, srcBucket, srcObject) - // Do we have read quorum? - if !isDiskQuorum(errs, xl.readQuorum) { - return ObjectInfo{}, traceError(InsufficientReadQuorum{}, errs...) - } - if reducedErr := reduceReadQuorumErrs(errs, objectOpIgnoredErrs, xl.readQuorum); reducedErr != nil { return ObjectInfo{}, toObjectErr(reducedErr, srcBucket, srcObject) } @@ -158,11 +149,6 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i // Read metadata associated with the object from all disks. metaArr, errs := readAllXLMetadata(xl.storageDisks, bucket, object) - // Do we have read quorum? - if !isDiskQuorum(errs, xl.readQuorum) { - return traceError(InsufficientReadQuorum{}, errs...) - } - if reducedErr := reduceReadQuorumErrs(errs, objectOpIgnoredErrs, xl.readQuorum); reducedErr != nil { return toObjectErr(reducedErr, bucket, object) } @@ -198,8 +184,14 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i return traceError(InvalidRange{startOffset, length, xlMeta.Stat.Size}) } + // Calculate endOffset according to length + endOffset := startOffset + if length > 0 { + endOffset += length - 1 + } + // Get last part index to read given length. - lastPartIndex, _, err := xlMeta.ObjectToPartOffset(startOffset + length - 1) + lastPartIndex, _, err := xlMeta.ObjectToPartOffset(endOffset) if err != nil { return traceError(InvalidRange{startOffset, length, xlMeta.Stat.Size}) } @@ -210,19 +202,22 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i // Object cache enabled block. if xlMeta.Stat.Size > 0 && xl.objCacheEnabled { // Validate if we have previous cache. - var cachedBuffer io.ReadSeeker + var cachedBuffer io.ReaderAt cachedBuffer, err = xl.objCache.Open(path.Join(bucket, object), modTime) - if err == nil { // Cache hit. - // Advance the buffer to offset as if it was read. - if _, err = cachedBuffer.Seek(startOffset, 0); err != nil { // Seek to the offset. - return traceError(err) - } - // Write the requested length. - if _, err = io.CopyN(writer, cachedBuffer, length); err != nil { + if err == nil { // Cache hit + // Create a new section reader, starting at an offset with length. + reader := io.NewSectionReader(cachedBuffer, startOffset, length) + + // Copy the data out. + if _, err = io.Copy(writer, reader); err != nil { return traceError(err) } + + // Success. return nil + } // Cache miss. + // For unknown error, return and error out. if err != objcache.ErrKeyNotFoundInCache { return traceError(err) @@ -281,7 +276,7 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i // Set checksum algo only once, while it is possible to have // different algos per block because of our `xl.json`. // It is not a requirement, set this only once for all the disks. - if ckSumAlgo != "" { + if ckSumAlgo == "" { ckSumAlgo = ckSumInfo.Algorithm } } @@ -409,12 +404,12 @@ func rename(disks []StorageAPI, srcBucket, srcEntry, dstBucket, dstEntry string, // We can safely allow RenameFile errors up to len(xl.storageDisks) - xl.writeQuorum // otherwise return failure. Cleanup successful renames. - if !isDiskQuorum(errs, quorum) { + err := reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, quorum) + if errorCause(err) == errXLWriteQuorum { // Undo all the partial rename operations. undoRename(disks, srcBucket, srcEntry, dstBucket, dstEntry, isDir, errs) - return traceError(errXLWriteQuorum) } - return reduceWriteQuorumErrs(errs, objectOpIgnoredErrs, quorum) + return err } // renamePart - renames a part of the source object to the destination @@ -455,7 +450,6 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. } uniqueID := mustGetUUID() - tempErasureObj := path.Join(uniqueID, "part.1") tempObj := uniqueID // Initialize md5 writer. @@ -506,40 +500,115 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. // Tee reader combines incoming data stream and md5, data read from input stream is written to md5. teeReader := io.TeeReader(limitDataReader, mw) - // Initialize xl meta. + // Initialize parts metadata + partsMetadata := make([]xlMetaV1, len(xl.storageDisks)) + xlMeta := newXLMetaV1(object, xl.dataBlocks, xl.parityBlocks) - onlineDisks := getOrderedDisks(xlMeta.Erasure.Distribution, xl.storageDisks) + // Initialize xl meta. + for index := range partsMetadata { + partsMetadata[index] = xlMeta + } + + // Order disks according to erasure distribution + onlineDisks := getOrderedDisks(partsMetadata[0].Erasure.Distribution, xl.storageDisks) // Delete temporary object in the event of failure. // If PutObject succeeded there would be no temporary // object to delete. defer xl.deleteObject(minioMetaTmpBucket, tempObj) - if size > 0 { - for _, disk := range onlineDisks { - if disk != nil { - actualSize := xl.sizeOnDisk(size, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks) - disk.PrepareFile(minioMetaTmpBucket, tempErasureObj, actualSize) + // Total size of the written object + sizeWritten := int64(0) + + // Read data and split into parts - similar to multipart mechanism + for partIdx := 1; ; partIdx++ { + // Compute part name + partName := "part." + strconv.Itoa(partIdx) + // Compute the path of current part + tempErasureObj := path.Join(uniqueID, partName) + + // Calculate the size of the current part, if size is unknown, curPartSize wil be unknown too. + // allowEmptyPart will always be true if this is the first part and false otherwise. + var curPartSize int64 + curPartSize, err = getPartSizeFromIdx(size, globalPutPartSize, partIdx) + if err != nil { + return ObjectInfo{}, toObjectErr(err, bucket, object) + } + + // Prepare file for eventual optimization in the disk + if curPartSize > 0 { + // Calculate the real size of the part in the disk and prepare it for eventual optimization + actualSize := xl.sizeOnDisk(curPartSize, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks) + for _, disk := range onlineDisks { + if disk != nil { + disk.PrepareFile(minioMetaTmpBucket, tempErasureObj, actualSize) + } } } - } - // Erasure code data and write across all disks. - sizeWritten, checkSums, err := erasureCreateFile(onlineDisks, minioMetaTmpBucket, tempErasureObj, teeReader, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks, xlMeta.Erasure.ParityBlocks, bitRotAlgo, xl.writeQuorum) - if err != nil { - return ObjectInfo{}, toObjectErr(err, minioMetaTmpBucket, tempErasureObj) - } - // Should return IncompleteBody{} error when reader has fewer bytes - // than specified in request header. - if sizeWritten < size { - return ObjectInfo{}, traceError(IncompleteBody{}) + // partReader streams at most maximum part size + partReader := io.LimitReader(teeReader, globalPutPartSize) + + // Allow creating empty earsure file only when this is the first part. This flag is useful + // when size == -1 because in this case, we are not able to predict how many parts we will have. + allowEmptyPart := partIdx == 1 + + // Erasure code data and write across all disks. + partSizeWritten, checkSums, erasureErr := erasureCreateFile(onlineDisks, minioMetaTmpBucket, tempErasureObj, partReader, allowEmptyPart, partsMetadata[0].Erasure.BlockSize, partsMetadata[0].Erasure.DataBlocks, partsMetadata[0].Erasure.ParityBlocks, bitRotAlgo, xl.writeQuorum) + if erasureErr != nil { + return ObjectInfo{}, toObjectErr(erasureErr, minioMetaTmpBucket, tempErasureObj) + } + + // Should return IncompleteBody{} error when reader has fewer bytes + // than specified in request header. + if partSizeWritten < int64(curPartSize) { + return ObjectInfo{}, traceError(IncompleteBody{}) + } + + // Update the total written size + sizeWritten += partSizeWritten + + // If erasure stored some data in the loop or created an empty file + if partSizeWritten > 0 || allowEmptyPart { + for index := range partsMetadata { + // Add the part to xl.json. + partsMetadata[index].AddObjectPart(partIdx, partName, "", partSizeWritten) + // Add part checksum info to xl.json. + partsMetadata[index].Erasure.AddCheckSumInfo(checkSumInfo{ + Name: partName, + Hash: checkSums[index], + Algorithm: bitRotAlgo, + }) + } + } + + // If we didn't write anything or we know that the next part doesn't have any + // data to write, we should quit this loop immediately + if partSizeWritten == 0 { + break + } + + // Check part size for the next index. + var partSize int64 + partSize, err = getPartSizeFromIdx(size, globalPutPartSize, partIdx+1) + if err != nil { + return ObjectInfo{}, toObjectErr(err, bucket, object) + } + if partSize == 0 { + break + } } // For size == -1, perhaps client is sending in chunked encoding // set the size as size that was actually written. if size == -1 { size = sizeWritten + } else { + // Check if stored data satisfies what is asked + if sizeWritten < size { + return ObjectInfo{}, traceError(IncompleteBody{}) + } } // Save additional erasureMetadata. @@ -598,22 +667,11 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. } // Fill all the necessary metadata. - xlMeta.Meta = metadata - xlMeta.Stat.Size = size - xlMeta.Stat.ModTime = modTime - - // Add the final part. - xlMeta.AddObjectPart(1, "part.1", newMD5Hex, xlMeta.Stat.Size) - - partsMetadata := make([]xlMetaV1, len(xl.storageDisks)) // Update `xl.json` content on each disks. for index := range partsMetadata { - partsMetadata[index] = xlMeta - partsMetadata[index].Erasure.AddCheckSumInfo(checkSumInfo{ - Name: "part.1", - Hash: checkSums[index], - Algorithm: bitRotAlgo, - }) + partsMetadata[index].Meta = metadata + partsMetadata[index].Stat.Size = size + partsMetadata[index].Stat.ModTime = modTime } // Write unique `xl.json` for each disk. @@ -633,6 +691,10 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. newBuffer.Close() } + // Object info is the same in all disks, so we can pick the first meta + // of the first disk + xlMeta = partsMetadata[0] + objInfo = ObjectInfo{ IsDir: false, Bucket: bucket, @@ -677,13 +739,7 @@ func (xl xlObjects) deleteObject(bucket, object string) error { // Wait for all routines to finish. wg.Wait() - // Do we have write quorum? - if !isDiskQuorum(dErrs, xl.writeQuorum) { - // Return errXLWriteQuorum if errors were more than allowed write quorum. - return traceError(errXLWriteQuorum) - } - - return nil + return reduceWriteQuorumErrs(dErrs, objectOpIgnoredErrs, xl.writeQuorum) } // DeleteObject - deletes an object, this call doesn't necessary reply diff --git a/cmd/xl-v1-utils.go b/cmd/xl-v1-utils.go index e2309483c..ecedbad1e 100644 --- a/cmd/xl-v1-utils.go +++ b/cmd/xl-v1-utils.go @@ -17,6 +17,7 @@ package cmd import ( + "errors" "hash/crc32" "path" "sync" @@ -82,23 +83,6 @@ func reduceWriteQuorumErrs(errs []error, ignoredErrs []error, writeQuorum int) ( return reduceQuorumErrs(errs, ignoredErrs, writeQuorum, errXLWriteQuorum) } -// List of all errors which are ignored while verifying quorum. -var quorumIgnoredErrs = append(baseIgnoredErrs, errDiskAccessDenied) - -// Validates if we have quorum based on the errors related to disk only. -// Returns 'true' if we have quorum, 'false' if we don't. -func isDiskQuorum(errs []error, minQuorumCount int) bool { - var count int - errs = errorsCause(errs) - for _, err := range errs { - // Check if the error can be ignored for quorum verification. - if !isErrIgnored(err, quorumIgnoredErrs...) { - count++ - } - } - return count >= minQuorumCount -} - // Similar to 'len(slice)' but returns the actual elements count // skipping the unallocated elements. func diskCount(disks []StorageAPI) int { @@ -343,3 +327,36 @@ func getOrderedDisks(distribution []int, disks []StorageAPI) (orderedDisks []Sto } return orderedDisks } + +// Errors specifically generated by getPartSizeFromIdx function. +var ( + errPartSizeZero = errors.New("Part size cannot be zero") + errPartSizeIndex = errors.New("Part index cannot be smaller than 1") +) + +// getPartSizeFromIdx predicts the part size according to its index. It also +// returns -1 when totalSize is also -1. +func getPartSizeFromIdx(totalSize int64, partSize int64, partIndex int) (int64, error) { + if partSize == 0 { + return 0, traceError(errPartSizeZero) + } + if partIndex < 1 { + return 0, traceError(errPartSizeIndex) + } + switch totalSize { + case -1, 0: + return totalSize, nil + } + // Compute the total count of parts + partsCount := totalSize/partSize + 1 + // Return the part's size + switch { + case int64(partIndex) < partsCount: + return partSize, nil + case int64(partIndex) == partsCount: + // Size of last part + return totalSize % partSize, nil + default: + return 0, nil + } +} diff --git a/cmd/xl-v1-utils_test.go b/cmd/xl-v1-utils_test.go index 1bada5408..bf6f2205b 100644 --- a/cmd/xl-v1-utils_test.go +++ b/cmd/xl-v1-utils_test.go @@ -22,6 +22,8 @@ import ( "strconv" "testing" "time" + + humanize "github.com/dustin/go-humanize" ) // Tests caclculating disk count. @@ -325,3 +327,59 @@ func TestGetXLMetaV1GJson10(t *testing.T) { } compareXLMetaV1(t, unMarshalXLMeta, gjsonXLMeta) } + +// Test the predicted part size from the part index +func TestGetPartSizeFromIdx(t *testing.T) { + // Create test cases + testCases := []struct { + totalSize int64 + partSize int64 + partIndex int + expectedSize int64 + }{ + // Total size is - 1 + {-1, 10, 1, -1}, + // Total size is zero + {0, 10, 1, 0}, + // part size 2MiB, total size 4MiB + {4 * humanize.MiByte, 2 * humanize.MiByte, 1, 2 * humanize.MiByte}, + {4 * humanize.MiByte, 2 * humanize.MiByte, 2, 2 * humanize.MiByte}, + {4 * humanize.MiByte, 2 * humanize.MiByte, 3, 0}, + // part size 2MiB, total size 5MiB + {5 * humanize.MiByte, 2 * humanize.MiByte, 1, 2 * humanize.MiByte}, + {5 * humanize.MiByte, 2 * humanize.MiByte, 2, 2 * humanize.MiByte}, + {5 * humanize.MiByte, 2 * humanize.MiByte, 3, 1 * humanize.MiByte}, + {5 * humanize.MiByte, 2 * humanize.MiByte, 4, 0}, + } + + for i, testCase := range testCases { + s, err := getPartSizeFromIdx(testCase.totalSize, testCase.partSize, testCase.partIndex) + if err != nil { + t.Errorf("Test %d: Expected to pass but failed. %s", i+1, err) + } + if err == nil && s != testCase.expectedSize { + t.Errorf("Test %d: The calculated part size is incorrect: expected = %d, found = %d\n", i+1, testCase.expectedSize, s) + } + } + + testCasesFailure := []struct { + totalSize int64 + partSize int64 + partIndex int + err error + }{ + // partSize is 0, error. + {10, 0, 1, errPartSizeZero}, + {10, 1, 0, errPartSizeIndex}, + } + + for i, testCaseFailure := range testCasesFailure { + _, err := getPartSizeFromIdx(testCaseFailure.totalSize, testCaseFailure.partSize, testCaseFailure.partIndex) + if err == nil { + t.Errorf("Test %d: Expected to failed but passed. %s", i+1, err) + } + if err != nil && errorCause(err) != testCaseFailure.err { + t.Errorf("Test %d: Expected err %s, but got %s", i+1, testCaseFailure.err, errorCause(err)) + } + } +} diff --git a/cmd/xl-v1.go b/cmd/xl-v1.go index a94cdd05a..4f6083d75 100644 --- a/cmd/xl-v1.go +++ b/cmd/xl-v1.go @@ -244,7 +244,7 @@ func getStorageInfo(disks []StorageAPI) StorageInfo { Free: validDisksInfo[0].Free * int64(onlineDisks) / 2, } - storageInfo.Backend.Type = XL + storageInfo.Backend.Type = Erasure storageInfo.Backend.OnlineDisks = onlineDisks storageInfo.Backend.OfflineDisks = offlineDisks return storageInfo diff --git a/docs/admin-api/management-api.md b/docs/admin-api/README.md similarity index 89% rename from docs/admin-api/management-api.md rename to docs/admin-api/README.md index 90f38b848..c8a045528 100644 --- a/docs/admin-api/management-api.md +++ b/docs/admin-api/README.md @@ -66,9 +66,9 @@ ### Lock Management APIs * ListLocks - - GET /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time + - GET /?lock&bucket=mybucket&prefix=myprefix&duration=duration - x-minio-operation: list - - Response: On success 200, json encoded response containing all locks held, older than rel_time. e.g, older than 3 hours. + - Response: On success 200, json encoded response containing all locks held, for longer than duration. - Possible error responses - ErrInvalidBucketName @@ -95,7 +95,7 @@ - ErrInvalidDuration InvalidDuration - Relative duration provided in the request is invalid. + Duration provided in the request is invalid. / @@ -105,9 +105,9 @@ * ClearLocks - - POST /?lock&bucket=mybucket&prefix=myprefix&older-than=rel_time + - POST /?lock&bucket=mybucket&prefix=myprefix&duration=duration - x-minio-operation: clear - - Response: On success 200, json encoded response containing all locks cleared, older than rel_time. e.g, older than 3 hours. + - Response: On success 200, json encoded response containing all locks cleared, for longer than duration. - Possible error responses, similar to errors listed in ListLocks. - ErrInvalidBucketName - ErrInvalidObjectName diff --git a/docs/backend/README.md b/docs/backend/README.md index c0412b288..548234b37 100644 --- a/docs/backend/README.md +++ b/docs/backend/README.md @@ -1,6 +1,8 @@ ## Backends -Minio currently implements two types of backends namely. +Minio currently implements two types of backends. -- Filesystem layer (fs). -- ErasureCode layer (XL). +| Minio | FS | Erasure | Stability | +|:-----------:|:----:|:----:|:---:| +| Standalone | x | x | Stable | +| Distributed | x | x | Stable | diff --git a/docs/bucket/notifications/README.md b/docs/bucket/notifications/README.md new file mode 100644 index 000000000..82e299342 --- /dev/null +++ b/docs/bucket/notifications/README.md @@ -0,0 +1,548 @@ +# Minio Bucket Notification Guide [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) + +Minio server supports Amazon S3 compatible bucket event notification for the following targets + +| Notification Targets| +|:---| +| [`AMQP`](#AMQP) | +| [`Elasticsearch`](#Elasticsearch) | +| [`Redis`](#Redis) | +| [`NATS`](#NATS) | +| [`PostgreSQL`](#PostgreSQL) | +| [`Apache Kafka`](#apache-kafka) | +| [`Webhooks`](#webhooks) | + +## Prerequisites + +* Install and configure Minio Server from [here](http://docs.minio.io/docs/minio). +* Install and configure Minio Client from [here](https://docs.minio.io/docs/minio-client-quickstart-guide). + + +## Publish Minio events via AMQP + +Install RabbitMQ from [here](https://www.rabbitmq.com/). + +### Step 1: Add AMQP endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the AMQP configuration block in ``config.json`` as follows: + +```json +"amqp": { + "1": { + "enable": true, + "url": "amqp://myuser:mypassword@localhost:5672", + "exchange": "bucketevents", + "routingKey": "bucketlogs", + "exchangeType": "fanout", + "mandatory": false, + "immediate": false, + "durable": false, + "internal": false, + "noWait": false, + "autoDeleted": false + } +} +``` + +Restart Minio server to reflect config changes. Minio supports all the exchanges available in [RabbitMQ](https://www.rabbitmq.com/). For this setup, we are using ``fanout`` exchange. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded or deleted ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:amqp``. To understand more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc events add myminio/images arn:minio:sqs:us-east-1:1:amqp --suffix .jpg +mc events list myminio/images +arn:minio:sqs:us-east-1:1:amqp s3:ObjectCreated:*,s3:ObjectRemoved:* Filter: suffix=”.jpg” +``` + +### Step 3: Test on RabbitMQ + +The python program below waits on the queue exchange ``bucketevents`` and prints event notifications on the console. We use [Pika Python Client](https://www.rabbitmq.com/tutorials/tutorial-three-python.html) library to do this. + +```py +#!/usr/bin/env python +import pika + +connection = pika.BlockingConnection(pika.ConnectionParameters( + host='localhost')) +channel = connection.channel() + +channel.exchange_declare(exchange='bucketevents', + type='fanout') + +result = channel.queue_declare(exclusive=False) +queue_name = result.method.queue + +channel.queue_bind(exchange='bucketevents', + queue=queue_name) + +print(' [*] Waiting for logs. To exit press CTRL+C') + +def callback(ch, method, properties, body): + print(" [x] %r" % body) + +channel.basic_consume(callback, + queue=queue_name, + no_ack=False) + +channel.start_consuming() +``` + +Execute this example python program to watch for RabbitMQ events on the console. + +```py +python rabbit.py +``` + +Open another terminal and upload a JPEG image into ``images`` bucket. + +``` +mc cp myphoto.jpg myminio/images +``` + +You should receive the following event notification via RabbitMQ once the upload completes. + +```py +python rabbit.py +‘{“Records”:[{“eventVersion”:”2.0",”eventSource”:”aws:s3",”awsRegion”:”us-east-1",”eventTime”:”2016–09–08T22:34:38.226Z”,”eventName”:”s3:ObjectCreated:Put”,”userIdentity”:{“principalId”:”minio”},”requestParameters”:{“sourceIPAddress”:”10.1.10.150:44576"},”responseElements”:{},”s3":{“s3SchemaVersion”:”1.0",”configurationId”:”Config”,”bucket”:{“name”:”images”,”ownerIdentity”:{“principalId”:”minio”},”arn”:”arn:aws:s3:::images”},”object”:{“key”:”myphoto.jpg”,”size”:200436,”sequencer”:”147279EAF9F40933"}}}],”level”:”info”,”msg”:””,”time”:”2016–09–08T15:34:38–07:00"}\n +``` + + +## Publish Minio events via Elasticsearch + +Install Elasticsearch 2.4 from [here](https://www.elastic.co/downloads/past-releases/elasticsearch-2-4-0). + +## Recipe steps + +### Step 1: Add Elasticsearch endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the Elasticsearch configuration block in ``config.json`` as follows: + +```json +"elasticsearch": { + "1": { + "enable": true, + "url": "http://127.0.0.1:9200", + "index": "bucketevents" + } +}, +``` + +Restart Minio server to reflect config changes. ``bucketevents`` is the index used by Elasticsearch. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded or deleted from ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:elasticsearch``. To understand more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc events add myminio/images arn:minio:sqs:us-east-1:1:elasticsearch --suffix .jpg +mc events list myminio/images +arn:minio:sqs:us-east-1:1:elasticsearch s3:ObjectCreated:*,s3:ObjectRemoved:* Filter: suffix=”.jpg” +``` + +### Step 3: Test on Elasticsearch + +Upload a JPEG image into ``images`` bucket, this is the bucket which has been configured for event notification. + +``` +mc cp myphoto.jpg myminio/images +``` + +Run ``curl`` to see new index name ``bucketevents`` in your Elasticsearch setup. + +``` +curl -XGET '127.0.0.1:9200/_cat/indices?v' +health status index pri rep docs.count docs.deleted store.size pri.store.size +yellow open bucketevents 5 1 1 0 7.8kb 7.8kb +``` + +Use curl to view contents of ``bucketevents`` index. + +``` +curl -XGET '127.0.0.1:9200/bucketevents/_search?pretty=1' +{ + "took" : 3, + "timed_out" : false, + "_shards" : { + "total" : 5, + "successful" : 5, + "failed" : 0 + }, + "hits" : { + "total" : 1, + "max_score" : 1.0, + "hits" : [ { + "_index" : "bucketevents", + "_type" : "event", + "_id" : "AVcRVOlwe-uNB1tfj6bx", + "_score" : 1.0, + "_source" : { + "Records" : [ { + "eventVersion" : "2.0", + "eventSource" : "aws:s3", + "awsRegion" : "us-east-1", + "eventTime" : "2016-09-09T23:42:39.977Z", + "eventName" : "s3:ObjectCreated:Put", + "userIdentity" : { + "principalId" : "minio" + }, + "requestParameters" : { + "sourceIPAddress" : "10.1.10.150:52140" + }, + "responseElements" : { }, + "s3" : { + "s3SchemaVersion" : "1.0", + "configurationId" : "Config", + "bucket" : { + "name" : "images", + "ownerIdentity" : { + "principalId" : "minio" + }, + "arn" : "arn:aws:s3:::images" + }, + "object" : { + "key" : "myphoto.jpg", + "size" : 200436, + "sequencer" : "1472CC35E6971AF3" + } + } + } ] + } + } ] + } +} +``` + +``curl`` output above states that an Elasticsearch index has been successfully created with notification contents. + + +## Publish Minio events via Redis + +Install Redis from [here](http://redis.io/download). + +### Step 1: Add Redis endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the Redis configuration block in ``config.json`` as follows: + +```json +"redis": { + "1": { + "enable": true, + "address": "127.0.0.1:6379", + "password": "yoursecret", + "key": "bucketevents" + } +} +``` + +Restart Minio server to reflect config changes. ``bucketevents`` is the key used by Redis in this example. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded or deleted from ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:redis``. To understand more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc events add myminio/images arn:minio:sqs:us-east-1:1:redis --suffix .jpg +mc events list myminio/images +arn:minio:sqs:us-east-1:1:redis s3:ObjectCreated:*,s3:ObjectRemoved:* Filter: suffix=”.jpg” +``` + +### Step 3: Test on Redis + +Redis comes with a handy command line interface ``redis-cli`` to print all notifications on the console. + +``` +redis-cli -a yoursecret +``` + +Open another terminal and upload a JPEG image into ``images`` bucket. + +``` +mc cp myphoto.jpg myminio/images +``` + +``redis-cli`` prints event notification to the console. + +``` +redis-cli -a yoursecret +127.0.0.1:6379> monitor +OK +1474321638.556108 [0 127.0.0.1:40190] "AUTH" "yoursecret" +1474321638.556477 [0 127.0.0.1:40190] "RPUSH" "bucketevents" "{\"Records\":[{\"eventVersion\":\"2.0\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2016-09-19T21:47:18.555Z\",\"eventName\":\"s3:ObjectCreated:Put\",\"userIdentity\":{\"principalId\":\"minio\"},\"requestParameters\":{\"sourceIPAddress\":\"[::1]:39250\"},\"responseElements\":{},\"s3\":{\"s3SchemaVersion\":\"1.0\",\"configurationId\":\"Config\",\"bucket\":{\"name\":\"images\",\"ownerIdentity\":{\"principalId\":\"minio\"},\"arn\":\"arn:aws:s3:::images\"},\"object\":{\"key\":\"myphoto.jpg\",\"size\":23745,\"sequencer\":\"1475D7B80ECBD853\"}}}],\"level\":\"info\",\"msg\":\"\",\"time\":\"2016-09-19T14:47:18-07:00\"}\n" +``` + + +## Publish Minio events via NATS + +Install NATS from [here](http://nats.io/). + +### Step 1: Add NATS endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the NATS configuration block in ``config.json`` as follows: + +``` +"nats": { + "1": { + "enable": true, + "address": "0.0.0.0:4222", + "subject": "bucketevents", + "username": "yourusername", + "password": "yoursecret", + "token": "", + "secure": false, + "pingInterval": 0 + } +}, +``` + +Restart Minio server to reflect config changes. ``bucketevents`` is the subject used by NATS in this example. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded or deleted from ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:nats``. To understand more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc events add myminio/images arn:minio:sqs:us-east-1:1:nats --suffix .jpg +mc events list myminio/images +arn:minio:sqs:us-east-1:1:nats s3:ObjectCreated:*,s3:ObjectRemoved:* Filter: suffix=”.jpg” +``` + +### Step 3: Test on NATS + +Using this program below we can log the bucket notification added to NATS. + +```go +package main + +// Import Go and NATS packages +import ( + "log" + "runtime" + + "github.com/nats-io/nats" +) + +func main() { + + // Create server connection + natsConnection, _ := nats.Connect("nats://yourusername:yoursecret@localhost:4222") + log.Println("Connected") + + // Subscribe to subject + log.Printf("Subscribing to subject 'bucketevents'\n") + natsConnection.Subscribe("bucketevents", func(msg *nats.Msg) { + + // Handle the message + log.Printf("Received message '%s\n", string(msg.Data)+"'") + }) + + // Keep the connection alive + runtime.Goexit() +} +``` + +``` +go run nats.go +2016/10/12 06:39:18 Connected +2016/10/12 06:39:18 Subscribing to subject 'bucketevents' +``` + +Open another terminal and upload a JPEG image into ``images`` bucket. + +``` +mc cp myphoto.jpg myminio/images +``` + +The example ``nats.go`` program prints event notification to console. + +``` +go run nats.go +2016/10/12 06:51:26 Connected +2016/10/12 06:51:26 Subscribing to subject 'bucketevents' +2016/10/12 06:51:33 Received message '{"EventType":"s3:ObjectCreated:Put","Key":"images/myphoto.jpg","Records":[{"eventVersion":"2.0","eventSource":"aws:s3","awsRegion":"us-east-1","eventTime":"2016-10-12T13:51:33Z","eventName":"s3:ObjectCreated:Put","userIdentity":{"principalId":"minio"},"requestParameters":{"sourceIPAddress":"[::1]:57106"},"responseElements":{},"s3":{"s3SchemaVersion":"1.0","configurationId":"Config","bucket":{"name":"images","ownerIdentity":{"principalId":"minio"},"arn":"arn:aws:s3:::images"},"object":{"key":"myphoto.jpg","size":56060,"eTag":"1d97bf45ecb37f7a7b699418070df08f","sequencer":"147CCD1AE054BFD0"}}}],"level":"info","msg":"","time":"2016-10-12T06:51:33-07:00"} +``` + + +## Publish Minio events via PostgreSQL + +Install PostgreSQL from [here](https://www.postgresql.org/). + +### Step 1: Add PostgreSQL endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the PostgreSQL configuration block in ``config.json`` as follows: + +``` +"postgresql": { + "1": { + "enable": true, + "connectionString": "", + "table": "bucketevents", + "host": "127.0.0.1", + "port": "5432", + "user": "postgres", + "password": "mypassword", + "database": "bucketevents_db" + } +} +``` + +Restart Minio server to reflect config changes. ``bucketevents`` is the database table used by PostgreSQL in this example. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded or deleted from ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:postgresql``. To understand more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc events add myminio/images arn:minio:sqs:us-east-1:1:postgresql --suffix .jpg +mc events list myminio/images +arn:minio:sqs:us-east-1:1:postgresql s3:ObjectCreated:*,s3:ObjectRemoved:* Filter: suffix=”.jpg” +``` + +### Step 3: Test on PostgreSQL + +Open another terminal and upload a JPEG image into ``images`` bucket. + +``` +mc cp myphoto.jpg myminio/images +``` + +Open PostgreSQL terminal to list the saved event notification logs. + +``` +bucketevents_db=# select * from bucketevents; + +key | value +--------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + images/myphoto.jpg | {"Records": [{"s3": {"bucket": {"arn": "arn:aws:s3:::images", "name": "images", "ownerIdentity": {"principalId": "minio"}}, "object": {"key": "myphoto.jpg", "eTag": "1d97bf45ecb37f7a7b699418070df08f", "size": 56060, "sequencer": "147CE57C70B31931"}, "configurationId": "Config", "s3SchemaVersion": "1.0"}, "awsRegion": "us-east-1", "eventName": "s3:ObjectCreated:Put", "eventTime": "2016-10-12T21:18:20Z", "eventSource": "aws:s3", "eventVersion": "2.0", "userIdentity": {"principalId": "minio"}, "responseElements": {}, "requestParameters": {"sourceIPAddress": "[::1]:39706"}}]} +(1 row) +``` + + +## Publish Minio events via kafka + +Install kafka from [here](http://kafka.apache.org/). + +### Step 1: Add kafka endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the kafka configuration block in ``config.json`` as follows: + +``` +"kafka": { + "1": { + "enable": true, + "brokers": ["localhost:9092"], + "topic": "bucketevents" + } +} +``` + +Restart Minio server to reflect config changes. ``bucketevents`` is the topic used by kafka in this example. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded or deleted from ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:kafka``. To understand more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc events add myminio/images arn:minio:sqs:us-east-1:1:kafka --suffix .jpg +mc events list myminio/images +arn:minio:sqs:us-east-1:1:kafka s3:ObjectCreated:*,s3:ObjectRemoved:* Filter: suffix=”.jpg” +``` + +### Step 3: Test on kafka + +We used [kafkacat](https://github.com/edenhill/kafkacat) to print all notifications on the console. + +``` +kafkacat -b localhost:9092 -t bucketevents +``` + +Open another terminal and upload a JPEG image into ``images`` bucket. + +``` +mc cp myphoto.jpg myminio/images +``` + +``kafkacat`` prints the event notification to the console. + +``` +kafkacat -b localhost:9092 -t bucketevents +{"EventType":"s3:ObjectCreated:Put","Key":"images/myphoto.jpg","Records":[{"eventVersion":"2.0","eventSource":"aws:s3","awsRegion":"us-east-1","eventTime":"2017-01-31T10:01:51Z","eventName":"s3:ObjectCreated:Put","userIdentity":{"principalId":"88QR09S7IOT4X1IBAQ9B"},"requestParameters":{"sourceIPAddress":"192.173.5.2:57904"},"responseElements":{"x-amz-request-id":"149ED2FD25589220","x-minio-origin-endpoint":"http://192.173.5.2:9000"},"s3":{"s3SchemaVersion":"1.0","configurationId":"Config","bucket":{"name":"images","ownerIdentity":{"principalId":"88QR09S7IOT4X1IBAQ9B"},"arn":"arn:aws:s3:::images"},"object":{"key":"myphoto.jpg","size":541596,"eTag":"04451d05b4faf4d62f3d538156115e2a","sequencer":"149ED2FD25589220"}}}],"level":"info","msg":"","time":"2017-01-31T15:31:51+05:30"} +``` + + +## Publish Minio events via Webhooks + +[Webhooks](https://en.wikipedia.org/wiki/Webhook) are a way to receive information when it happens, rather than continually polling for that data. + +### Step 1: Add Webhook endpoint to Minio + +The default location of Minio server configuration file is ``~/.minio/config.json``. Update the Webhook configuration block in ``config.json`` as follows + +``` +"webhook": { + "1": { + "enable": true, + "endpoint": "http://localhost:3000/" +} +``` +Here the endpoint is the server listening for webhook notifications. Save the file and restart the Minio server for changes to take effect. Note that the endpoint needs to be live and reachable when you restart your Minio server. + +### Step 2: Enable bucket notification using Minio client + +We will enable bucket event notification to trigger whenever a JPEG image is uploaded to ``images`` bucket on ``myminio`` server. Here ARN value is ``arn:minio:sqs:us-east-1:1:webhook``. To learn more about ARN please follow [AWS ARN](http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html) documentation. + +``` +mc mb myminio/images +mc mb myminio/images-thumbnail +mc events add myminio/images arn:minio:sqs:us-east-1:1:webhook — events put — suffix .jpg +``` + +Check if event notification is successfully configured by + +``` +mc events list myminio/images +``` + +You should get a response like this + +``` +arn:minio:sqs:us-east-1:1:webhook s3:ObjectCreated:* Filter: suffix=".jpg" +``` + +### Step 3: Test with Thumbnailer + +We used [Thumbnailer](https://github.com/minio/thumbnailer) to listen for Minio notifications when a new JPEG file is uploaded (HTTP PUT). Triggered by a notification, Thumbnailer uploads a thumbnail of new image to Minio server. To start with, download and install Thumbnailer. + +``` +git clone https://github.com/minio/thumbnailer/ +npm install +``` + +Then open the Thumbnailer config file at ``config/webhook.json`` and add the configuration for your Minio server and then start Thumbnailer by + +``` +NODE_ENV=webhook node thumbnail-webhook.js +``` + +Thumbnailer starts running at ``http://localhost:3000/``. Next, configure the Minio server to send notifications to this URL (as mentioned in step 1) and use ``mc`` to set up bucket notifications (as mentioned in step 2). Then upload a JPEG image to Minio server by + +``` +mc cp ~/images.jpg myminio/images +.../images.jpg: 8.31 KB / 8.31 KB ┃▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓┃ 100.00% 59.42 KB/s 0s +``` +Wait a few moments, then check the bucket’s contents with mc ls — you will see a thumbnail appear. + +``` +mc ls myminio/images-thumbnail +[2017-02-08 11:39:40 IST] 992B images-thumbnail.jpg +``` + + +*NOTE* If you are running [distributed Minio](https://docs.minio.io/docs/distributed-minio-quickstart-guide), modify ``~/.minio/config.json`` on all the nodes with your bucket event notification backend configuration. diff --git a/docs/bucket/policy/README.md b/docs/bucket/policy/README.md index b642de294..a738ff2c9 100644 --- a/docs/bucket/policy/README.md +++ b/docs/bucket/policy/README.md @@ -22,11 +22,14 @@ This package implements parsing and validating bucket access policies based on A StringEquals StringNotEquals + StringLike + StringNotLike Supported applicable condition keys for each conditions. s3:prefix s3:max-keys + aws:Referer ### Nested policy support. diff --git a/docs/configure-minio-with-gnutls-windows.md b/docs/configure-minio-with-gnutls-windows.md deleted file mode 100644 index b397e30d8..000000000 --- a/docs/configure-minio-with-gnutls-windows.md +++ /dev/null @@ -1,68 +0,0 @@ - -# Generate self signed certificate with GnuTLS under Windows - - -## 1. Install GnuTLS - -Download and decompress the Windows version of GnuTLS from [here](http://www.gnutls.org/download.html) - -Add the directory `gnutls-3.4.9-w64/bin` to your PATH environment and restart your console - -## 2. Generate private.key - -Run the following command to create `private.key` -``` -certtool.exe --generate-privkey --outfile private.key -``` - -## 3. Generate public.crt - -The easiest way is to generate certificate is to specify its information under a file. You can find an example below. We'll call that file `cert.cnf`. - -``` -# X.509 Certificate options -# -# DN options - -# The organization of the subject. -organization = "Example Inc." - -# The organizational unit of the subject. -#unit = "sleeping dept." - -# The state of the certificate owner. -state = "Example" - -# The country of the subject. Two letter code. -country = "EX" - -# The common name of the certificate owner. -cn = "Sally Certowner" - -# In how many days, counting from today, this certificate will expire. -expiration_days = 365 - -# X.509 v3 extensions - -# DNS name(s) of the server -dns_name = "localhost" - -# (Optional) Server IP address -ip_address = "127.0.0.1" - -# Whether this certificate will be used for a TLS server -tls_www_server - -# Whether this certificate will be used to encrypt data (needed -# in TLS RSA ciphersuites). Note that it is preferred to use different -# keys for encryption and signing. -encryption_key -``` - -Now, it is time to generate the public certificate using this command: - -```sh -certtool.exe --generate-self-signed --load-privkey private.key --template cert.cnf --outfile public.crt -``` - -That's it. diff --git a/docs/configure-minio-with-tls.md b/docs/configure-minio-with-tls.md deleted file mode 100644 index 840f5628c..000000000 --- a/docs/configure-minio-with-tls.md +++ /dev/null @@ -1,49 +0,0 @@ -# How to secure access to your Minio server with TLS [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) - -In this document, we will show how to configure your Minio servers with TLS certificates. Steps for Windows could be found [here](https://github.com/minio/minio/blob/master/docs/configure-minio-with-gnutls-windows.md). - -## 1. Prerequisites - -* Download Minio server from [here](https://docs.minio.io/docs/minio) - -## 2. Generate TLS certificate - -Minio supports only key/certificate in PEM format. - -### With Letsencrypt - -Please explore [here](https://docs.minio.io/docs/generate-let-s-encypt-certificate-using-concert-for-minio) - -### With generate_cert.go (self-signed certificate) - -You need to download [generate_cert.go](https://golang.org/src/crypto/tls/generate_cert.go?m=text) which is a simple go tool for generating self-signed certificates but works for the most of cases. - -`generate_cert.go` already provides SAN certificates with DNS and IP entries: - -```sh - go run generate_cert.go -ca --host "10.10.0.3" -``` - -### With OpenSSL: - -Generate the private key: -```sh -openssl genrsa -out private.key 1024 -``` - -Generate the self-signed certificate: -```sh -openssl req -new -x509 -days 3650 -key private.key -out public.crt -subj "/C=country/ST=state/L=location/O=organization/CN=domain" -``` - -## 3. Configure Minio with the generated certificate - -To make Minio aware about your generated key and certificate, you will need to put them under `certs` directory in your Minio config path (usually ~/.minio) using the names of `private.key` and `public.crt` for key and certificate files respectively. - -## 4. Install third parties CAs - -Minio can be configured to connect to other servers, whether Minio nodes or servers like NATs, Redis. If these servers use certificates that are not registered in one of the known certificates authorities, you can make Minio server trust these CAs by dropping these certificates under `~/.minio/certs/CAs/` in your Minio config path. - -# Explore Further -* [Minio Quickstart Guide](https://docs.minio.io/docs/minio-quickstart-guide) -* [Minio Client Complete Guide](https://docs.minio.io/docs/minio-client-complete-guide) diff --git a/docs/distributed/README.md b/docs/distributed/README.md index 04e4ab302..de8ba314b 100644 --- a/docs/distributed/README.md +++ b/docs/distributed/README.md @@ -22,21 +22,26 @@ As with Minio in stand-alone mode, distributed Minio has a per tenant limit of m Note that with distributed Minio you can play around with the number of nodes and drives as long as the limits are adhered to. For example, you can have 2 nodes with 4 drives each, 4 nodes with 4 drives each, 8 nodes with 2 drives each, and so on. +### Consistency Guarantees + +Minio follows strict **read-after-write** consistency model for all i/o operations both in distributed and standalone modes. + # Get started If you're aware of stand-alone Minio set up, the process remains largely the same, as the Minio server automatically switches to stand-alone or distributed mode, depending on the command line parameters. ## 1. Prerequisites -Install Minio - [Minio Quickstart Guide](https://docs.minio.io/docs/minio). +Install Minio - [Minio Quickstart Guide](https://docs.minio.io/docs/minio-quickstart-guide). ## 2. Run distributed Minio To start a distributed Minio instance, you just need to pass drive locations as parameters to the minio server command. Then, you’ll need to run the same command on all the participating nodes. -It is important to note here that all the nodes running distributed Minio need to have same access key and secret key. Otherwise nodes won't connect. To achieve this, you need to export access key and secret key as environment variables on all the nodes before executing Minio server command. - -Below examples will clarify further: +*Note* +- All the nodes running distributed Minio need to have same access key and secret key for the nodes to connect. To achieve this, you need to export access key and secret key as environment variables on all the nodes before executing Minio server command. +- Disks used for Minio distributed should be fresh with no pre-existing data. +- The IP addresses and drive paths below are for demonstration purposes only, you need to replace these with the actual IP addresses and drive paths/folders. Example 1: Start distributed Minio instance with 1 drive each on 8 nodes, by running this command on all the 8 nodes. @@ -68,8 +73,6 @@ minio server http://192.168.1.11/export1 http://192.168.1.11/export2 \ ![Distributed Minio, 4 nodes with 4 disks each](https://raw.githubusercontent.com/minio/minio/master/docs/screenshots/Architecture-diagram_distributed_16.png) -Note that these IP addresses and drive paths are for demonstration purposes only, you need to replace these with the actual IP addresses and drive paths. - ## 3. Test your setup To test this setup, access the Minio server via browser or [`mc`](https://docs.minio.io/docs/minio-client-quickstart-guide). You’ll see the combined capacity of all the storage drives as the capacity of this drive. diff --git a/docs/minio-limitations.md b/docs/minio-limitations.md index 539e6ef9f..9e59ee747 100644 --- a/docs/minio-limitations.md +++ b/docs/minio-limitations.md @@ -1,5 +1,4 @@ ## Minio Server Limits Per Tenant -We found the following APIs to be redundant or less useful outside of AWS. If you have a different view on any of the APIs we missed, please open a [github issue](https://github.com/minio/minio/issues). ### Erasure Code (Multiple Drives / Servers) @@ -31,20 +30,21 @@ We found the following APIs to be redundant or less useful outside of AWS. If yo |Maximum number of objects returned per list objects request| 1000| |Maximum number of multipart uploads returned per list multipart uploads request| 1000| +We found the following APIs to be redundant or less useful outside of AWS S3. If you have a different view on any of the APIs we missed, please open a [github issue](https://github.com/minio/minio/issues). + ### List of Amazon S3 Bucket API's not supported on Minio. -- BucketACL (Use bucket policies instead) -- BucketCORS (CORS enabled by default) -- BucketLifecycle (Not required for Minio's XL backend) -- BucketReplication (Use `mc mirror` instead) -- BucketVersions, BucketVersioning (Use `s3git`) -- BucketWebsite (Use `caddy` or `nginx`) -- BucketAnalytics, BucketMetrics, BucketLogging (Use bucket notification APIs) +- BucketACL (Use [bucket policies](http://docs.minio.io/docs/minio-client-complete-guide#policy) instead) +- BucketCORS (CORS enabled by default on all buckets for all HTTP verbs) +- BucketLifecycle (Not required for Minio erasure coded backend) +- BucketReplication (Use [`mc mirror`](http://docs.minio.io/docs/minio-client-complete-guide#mirror) instead) +- BucketVersions, BucketVersioning (Use [`s3git`](https://github.com/s3git/s3git)) +- BucketWebsite (Use [`caddy`](https://github.com/mholt/caddy) or [`nginx`](https://www.nginx.com/resources/wiki/)) +- BucketAnalytics, BucketMetrics, BucketLogging (Use [bucket notification](http://docs.minio.io/docs/minio-client-complete-guide#events) APIs) - BucketRequestPayment - BucketTagging ### List of Amazon S3 Object API's not supported on Minio. -- ObjectACL (Use bucket policies instead) +- ObjectACL (Use [bucket policies](http://docs.minio.io/docs/minio-client-complete-guide#policy) instead) - ObjectTorrent -- ObjectCopyPart diff --git a/docs/service/linux/README.md b/docs/service/linux/README.md new file mode 100644 index 000000000..84780b329 --- /dev/null +++ b/docs/service/linux/README.md @@ -0,0 +1,44 @@ +# Running Minio as a service on Linux + +## Install Minio service + +Systemctl is a controller for systemd system and service manager. This document assumes operating system to be Ubuntu 16.04 (LTS) with `systemctl`. + +Create a default minio startup config file at `/etc/default/minio`. `MINIO_VOLUMES` should be updated with the correct path. +``` +cat <> /etc/default/minio +# Local export path. +MINIO_VOLUMES="/mnt/export" +# Use if you want to run Minio on a custom port. +# MINIO_OPTS="--address :9001" + +EOT +``` + +Optionally you can also override your Minio access credentials as shown below. +``` +cat <> /etc/default/minio +# Access key of the server. +MINIO_ACCESS_KEY=YOUR-ACCESSKEY +# Secret key of the server. +MINIO_SECRET_KEY=YOUR-SECRETKEY + +EOT +``` + +Download `minio.service` into `/etc/systemd/system/` +``` +( cd /etc/systemd/system/; curl -O https://raw.githubusercontent.com/minio/minio-systemd/master/minio.service ) +``` + +## Enable Minio service + +Once we have successfully copied the `minio.service` we will enable it to start on boot. +``` +systemctl enable minio.service +``` + +## Disable Minio service +``` +systemctl disable minio.service +``` diff --git a/docs/running-minio-as-a-service-on-windows.md b/docs/service/windows/README.md similarity index 99% rename from docs/running-minio-as-a-service-on-windows.md rename to docs/service/windows/README.md index f459d6afe..3c10628bf 100644 --- a/docs/running-minio-as-a-service-on-windows.md +++ b/docs/service/windows/README.md @@ -23,7 +23,6 @@ It is a good (and secure) practice to create a new user, assign rights to the da ![Configure user](https://raw.githubusercontent.com/minio/minio/master/docs/screenshots/windows-configure-user.png) ## Delete Minio service - ``` c:\nssm.exe remove Minio ``` diff --git a/docs/tls/README.md b/docs/tls/README.md new file mode 100644 index 000000000..3025c161f --- /dev/null +++ b/docs/tls/README.md @@ -0,0 +1,127 @@ +# How to secure access to Minio server with TLS [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) + +In this document, we will configure Minio servers with TLS certificates for both Linux and Windows. + +## 1. Prerequisites + +* Download Minio server from [here](https://docs.minio.io/docs/minio) + +## 2. Generate TLS certificate + +### Linux + +Minio supports only key/certificate in PEM format on Linux. + +#### With Let's Encrypt + +Please explore [here](https://docs.minio.io/docs/generate-let-s-encypt-certificate-using-concert-for-minio) + +#### With generate_cert.go (self-signed certificate) + +You need to download [generate_cert.go](https://golang.org/src/crypto/tls/generate_cert.go?m=text) which is a simple go tool for generating self-signed certificates but works for the most of cases. + +`generate_cert.go` already provides SAN certificates with DNS and IP entries: + +```sh +go run generate_cert.go -ca --host "10.10.0.3" +``` + +#### With OpenSSL: + +Generate the private key: + +```sh +openssl genrsa -out private.key 1024 +``` + +Generate the self-signed certificate: + +```sh +openssl req -new -x509 -days 3650 -key private.key -out public.crt -subj "/C=country/ST=state/L=location/O=organization/CN=domain" +``` + +### Windows + +Minio only supports key/certificate in PEM format on Windows. Currently we do not yet support PFX certificates. + +#### Install GnuTLS + +Download and decompress the Windows version of GnuTLS from [here](http://www.gnutls.org/download.html) + +Make sure to add extracted GnuTLS binary path to your system path. + +``` +setx path "%path%;C:\Users\MyUser\Downloads\gnutls-3.4.9-w64\bin" +``` + +You may need to restart your powershell console for this to take affect. + +#### Generate private.key + +Run the following command to create `private.key` + +``` +certtool.exe --generate-privkey --outfile private.key +``` + +#### Generate public.crt + +Create a file `cert.cnf` with all the necessary information to generate a certificate. + +``` +# X.509 Certificate options +# +# DN options + +# The organization of the subject. +organization = "Example Inc." + +# The organizational unit of the subject. +#unit = "sleeping dept." + +# The state of the certificate owner. +state = "Example" + +# The country of the subject. Two letter code. +country = "EX" + +# The common name of the certificate owner. +cn = "Sally Certowner" + +# In how many days, counting from today, this certificate will expire. +expiration_days = 365 + +# X.509 v3 extensions + +# DNS name(s) of the server +dns_name = "localhost" + +# (Optional) Server IP address +ip_address = "127.0.0.1" + +# Whether this certificate will be used for a TLS server +tls_www_server + +# Whether this certificate will be used to encrypt data (needed +# in TLS RSA ciphersuites). Note that it is preferred to use different +# keys for encryption and signing. +encryption_key +``` + +Generate public certificate + +``` +certtool.exe --generate-self-signed --load-privkey private.key --template cert.cnf --outfile public.crt +``` + +## 3. Configure Minio with the generated certificate + +Copy the generated key and certificate under `certs` in your Minio config path (by default in your HOME directory `~/.minio` on Linux or `C:\Users\\.minio` on Windows) using the names `private.key` and `public.crt` for key and certificate files respectively. + +## 4. Install third-party CAs + +Minio can be configured to connect to other servers, whether Minio nodes or servers like NATs, Redis. If these servers use certificates that are not registered in one of the known certificates authorities, you can make Minio server trust these CAs by dropping these certificates under Minio config path (`~/.minio/certs/CAs/` on Linux or `C:\Users\\.minio\certs\CAs` on Windows). + +# Explore Further +* [Minio Quickstart Guide](https://docs.minio.io/docs/minio-quickstart-guide) +* [Minio Client Complete Guide](https://docs.minio.io/docs/minio-client-complete-guide) diff --git a/main.go b/main.go index 03814d857..43d2a73ed 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2016 Minio, Inc. + * Minio Cloud Storage, (C) 2016,2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,48 @@ package main // import "github.com/minio/minio" -import minio "github.com/minio/minio/cmd" +import ( + "fmt" + "os" + "runtime" + + version "github.com/hashicorp/go-version" + "github.com/minio/mc/pkg/console" + minio "github.com/minio/minio/cmd" +) + +const ( + // Minio requires at least Go v1.7 + minGoVersion = "1.7" + goVersionConstraint = ">= " + minGoVersion +) + +// Check if this binary is compiled with at least minimum Go version. +func checkGoVersion(goVersionStr string) error { + constraint, err := version.NewConstraint(goVersionConstraint) + if err != nil { + return fmt.Errorf("'%s': %s", goVersionConstraint, err) + } + + goVersion, err := version.NewVersion(goVersionStr) + if err != nil { + return err + } + + if !constraint.Check(goVersion) { + return fmt.Errorf("Minio is not compiled by Go %s. Please recompile accordingly.", + goVersionConstraint) + } + + return nil +} func main() { - minio.Main() + // When `go get` is used minimum Go version check is not triggered but it would have compiled it successfully. + // However such binary will fail at runtime, hence we also check Go version at runtime. + if err := checkGoVersion(runtime.Version()[2:]); err != nil { + console.Fatalln("Go runtime version check failed.", err) + } + + minio.Main(os.Args, os.Exit) } diff --git a/main_test.go b/main_test.go new file mode 100644 index 000000000..85b9b2e8e --- /dev/null +++ b/main_test.go @@ -0,0 +1,50 @@ +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "fmt" + "testing" +) + +func TestCheckGoVersion(t *testing.T) { + // Test success cases. + testCases := []struct { + version string + expectedErr error + }{ + {minGoVersion, nil}, + {minGoVersion + ".10", nil}, + {"1.6.8", fmt.Errorf("Minio is not compiled by Go >= 1.7. Please recompile accordingly.")}, + {"0.1", fmt.Errorf("Minio is not compiled by Go >= 1.7. Please recompile accordingly.")}, + {".1", fmt.Errorf("Malformed version: .1")}, + {"somejunk", fmt.Errorf("Malformed version: somejunk")}, + } + + for _, testCase := range testCases { + err := checkGoVersion(testCase.version) + if testCase.expectedErr == nil { + if err != nil { + t.Fatalf("expected: %v, got: %v", testCase.expectedErr, err) + } + } else if err == nil { + t.Fatalf("expected: %v, got: %v", testCase.expectedErr, err) + } else if testCase.expectedErr.Error() != err.Error() { + t.Fatalf("expected: %v, got: %v", testCase.expectedErr, err) + } + } +} diff --git a/pkg/disk/disk.go b/pkg/disk/disk.go index 4eae7c211..8b4265c39 100644 --- a/pkg/disk/disk.go +++ b/pkg/disk/disk.go @@ -27,3 +27,11 @@ type Info struct { Ffree int64 FSType string } + +func b2s(bs []int8) string { + b := make([]byte, len(bs)) + for i, v := range bs { + b[i] = byte(v) + } + return string(b) +} diff --git a/pkg/disk/disk_test.go b/pkg/disk/disk_test.go index 58858a4ff..a1a4915b1 100644 --- a/pkg/disk/disk_test.go +++ b/pkg/disk/disk_test.go @@ -1,5 +1,7 @@ +// +build !netbsd,!solaris + /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/pkg/disk/stat_nix.go b/pkg/disk/stat_bsd.go similarity index 85% rename from pkg/disk/stat_nix.go rename to pkg/disk/stat_bsd.go index 1c1a58a01..31aebd521 100644 --- a/pkg/disk/stat_nix.go +++ b/pkg/disk/stat_bsd.go @@ -1,7 +1,7 @@ -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin freebsd dragonfly /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,9 +34,6 @@ func GetInfo(path string) (info Info, err error) { info.Free = int64(s.Bsize) * int64(s.Bavail) info.Files = int64(s.Files) info.Ffree = int64(s.Ffree) - info.FSType, err = getFSType(path) - if err != nil { - return Info{}, err - } + info.FSType = getFSType(s.Fstypename) return info, nil } diff --git a/vendor/github.com/minio/blake2b-simd/compress_amd64.go b/pkg/disk/stat_fallback.go similarity index 64% rename from vendor/github.com/minio/blake2b-simd/compress_amd64.go rename to pkg/disk/stat_fallback.go index 4fc5e388c..7439135bb 100644 --- a/vendor/github.com/minio/blake2b-simd/compress_amd64.go +++ b/pkg/disk/stat_fallback.go @@ -1,5 +1,7 @@ +// +build netbsd solaris + /* - * Minio Cloud Storage, (C) 2016 Minio, Inc. + * Minio Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +16,9 @@ * limitations under the License. */ -package blake2b +package disk -func compress(d *digest, p []uint8) { - // Verifies if AVX2 or AVX is available, use optimized code path. - if avx2 { - compressAVX2(d, p) - } else if avx { - compressAVX(d, p) - } else if ssse3 { - compressSSE(d, p) - } else { - compressGeneric(d, p) - } +// GetInfo returns total and free bytes available in a directory, e.g. `/`. +func GetInfo(path string) (info Info, err error) { + return Info{}, nil } diff --git a/pkg/disk/type_unix.go b/pkg/disk/stat_linux.go similarity index 54% rename from pkg/disk/type_unix.go rename to pkg/disk/stat_linux.go index 3fe4cafb2..4106cd985 100644 --- a/pkg/disk/type_unix.go +++ b/pkg/disk/stat_linux.go @@ -1,7 +1,7 @@ -// +build freebsd +// +build linux /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,26 +19,21 @@ package disk import ( - "strconv" "syscall" ) -// fsType2StringMap - list of filesystems supported by donut on linux -var fsType2StringMap = map[string]string{ - "35": "UFS", -} - -// getFSType returns the filesystem type of the underlying mounted filesystem -func getFSType(path string) (string, error) { +// GetInfo returns total and free bytes available in a directory, e.g. `/`. +func GetInfo(path string) (info Info, err error) { s := syscall.Statfs_t{} - err := syscall.Statfs(path, &s) + err = syscall.Statfs(path, &s) if err != nil { - return "", err + return Info{}, err } - fsTypeHex := strconv.FormatInt(int64(s.Type), 16) - fsTypeString, ok := fsType2StringMap[fsTypeHex] - if ok == false { - return "UNKNOWN", nil - } - return fsTypeString, nil + info = Info{} + info.Total = int64(s.Bsize) * int64(s.Blocks) + info.Free = int64(s.Bsize) * int64(s.Bavail) + info.Files = int64(s.Files) + info.Ffree = int64(s.Ffree) + info.FSType = getFSType(int64(s.Type)) + return info, nil } diff --git a/pkg/disk/stat_openbsd.go b/pkg/disk/stat_openbsd.go new file mode 100644 index 000000000..3a8d43218 --- /dev/null +++ b/pkg/disk/stat_openbsd.go @@ -0,0 +1,39 @@ +// +build openbsd + +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package disk + +import ( + "syscall" +) + +// GetInfo returns total and free bytes available in a directory, e.g. `/`. +func GetInfo(path string) (info Info, err error) { + s := syscall.Statfs_t{} + err = syscall.Statfs(path, &s) + if err != nil { + return Info{}, err + } + info = Info{} + info.Total = int64(s.F_bsize) * int64(s.F_blocks) + info.Free = int64(s.F_bsize) * int64(s.F_bavail) + info.Files = int64(s.F_files) + info.Ffree = int64(s.F_ffree) + info.FSType = getFSType(s.F_fstypename) + return info, nil +} diff --git a/pkg/disk/type_darwin.go b/pkg/disk/type_bsd.go similarity index 55% rename from pkg/disk/type_darwin.go rename to pkg/disk/type_bsd.go index c000e1a08..0818f10d6 100644 --- a/pkg/disk/type_darwin.go +++ b/pkg/disk/type_bsd.go @@ -1,7 +1,7 @@ -// +build darwin +// +build darwin freebsd dragonfly openbsd /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,27 +18,7 @@ package disk -import ( - "strconv" - "syscall" -) - -// fsType2StrinMap - list of filesystems supported by donut -var fsType2StringMap = map[string]string{ - "11": "HFS", -} - // getFSType returns the filesystem type of the underlying mounted filesystem -func getFSType(path string) (string, error) { - s := syscall.Statfs_t{} - err := syscall.Statfs(path, &s) - if err != nil { - return "", err - } - fsTypeHex := strconv.FormatUint(uint64(s.Type), 16) - fsTypeString, ok := fsType2StringMap[fsTypeHex] - if !ok { - return "UNKNOWN", nil - } - return fsTypeString, nil +func getFSType(fstype [16]int8) string { + return b2s(fstype[:]) } diff --git a/pkg/disk/type_linux.go b/pkg/disk/type_linux.go index 4609c90b0..98dceb66f 100644 --- a/pkg/disk/type_linux.go +++ b/pkg/disk/type_linux.go @@ -1,7 +1,7 @@ // +build linux /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,7 @@ package disk -import ( - "strconv" - "syscall" -) +import "strconv" // fsType2StringMap - list of filesystems supported by donut on linux var fsType2StringMap = map[string]string{ @@ -40,16 +37,11 @@ var fsType2StringMap = map[string]string{ } // getFSType returns the filesystem type of the underlying mounted filesystem -func getFSType(path string) (string, error) { - s := syscall.Statfs_t{} - err := syscall.Statfs(path, &s) - if err != nil { - return "", err - } - fsTypeHex := strconv.FormatInt(int64(s.Type), 16) +func getFSType(ftype int64) string { + fsTypeHex := strconv.FormatInt(ftype, 16) fsTypeString, ok := fsType2StringMap[fsTypeHex] if ok == false { - return "UNKNOWN", nil + return "UNKNOWN" } - return fsTypeString, nil + return fsTypeString } diff --git a/pkg/lock/lock.go b/pkg/lock/lock.go index a72750fdc..f8632a667 100644 --- a/pkg/lock/lock.go +++ b/pkg/lock/lock.go @@ -89,14 +89,7 @@ func RLockedOpenFile(path string) (*RLockedFile, error) { } -// LockedFile represents a locked file, implements a helper -// method Size(), represents the size of the underlying object. +// LockedFile represents a locked file type LockedFile struct { *os.File - size int64 -} - -// Size - size of the underlying locked file. -func (l *LockedFile) Size() int64 { - return l.size } diff --git a/pkg/lock/lock_nix.go b/pkg/lock/lock_nix.go index 14263335d..537255c01 100644 --- a/pkg/lock/lock_nix.go +++ b/pkg/lock/lock_nix.go @@ -71,5 +71,5 @@ func LockedOpenFile(path string, flag int, perm os.FileMode) (*LockedFile, error } } - return &LockedFile{File: f, size: st.Size()}, nil + return &LockedFile{File: f}, nil } diff --git a/pkg/lock/lock_solaris.go b/pkg/lock/lock_solaris.go new file mode 100644 index 000000000..76aa769b6 --- /dev/null +++ b/pkg/lock/lock_solaris.go @@ -0,0 +1,83 @@ +// +build solaris + +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package lock + +import ( + "fmt" + "os" + "syscall" +) + +// LockedOpenFile - initializes a new lock and protects +// the file from concurrent access across mount points. +// This implementation doesn't support all the open +// flags and shouldn't be considered as replacement +// for os.OpenFile(). +func LockedOpenFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + var lock syscall.Flock_t + lock.Start = 0 + lock.Len = 0 + lock.Pid = 0 + + var lockType int16 + switch flag { + case syscall.O_RDONLY: + lockType = syscall.F_RDLCK + case syscall.O_WRONLY: + fallthrough + case syscall.O_RDWR: + fallthrough + case syscall.O_WRONLY | syscall.O_CREAT: + fallthrough + case syscall.O_RDWR | syscall.O_CREAT: + lockType = syscall.F_WRLCK + default: + return nil, fmt.Errorf("Unsupported flag (%d)", flag) + } + + lock.Type = lockType + lock.Whence = 0 + + f, err := os.OpenFile(path, flag, perm) + if err != nil { + return nil, err + } + + if err = syscall.FcntlFlock(f.Fd(), syscall.F_SETLKW, &lock); err != nil { + f.Close() + return nil, err + } + + st, err := os.Stat(path) + if err != nil { + f.Close() + return nil, err + } + + if st.IsDir() { + f.Close() + return nil, &os.PathError{ + Op: "open", + Path: path, + Err: syscall.EISDIR, + } + } + + return &LockedFile{f}, nil +} diff --git a/pkg/lock/lock_test.go b/pkg/lock/lock_test.go index 4c3547417..abc8e71c3 100644 --- a/pkg/lock/lock_test.go +++ b/pkg/lock/lock_test.go @@ -80,9 +80,6 @@ func TestRWLockedFile(t *testing.T) { if err != nil { t.Fatal(err) } - if rlk.Size() != 0 { - t.Fatal("File size should be zero", rlk.Size()) - } isClosed := rlk.IsClosed() if isClosed { t.Fatal("File ref count shouldn't be zero") diff --git a/pkg/lock/lock_windows.go b/pkg/lock/lock_windows.go index dcbb7ed33..04a00e093 100644 --- a/pkg/lock/lock_windows.go +++ b/pkg/lock/lock_windows.go @@ -65,7 +65,7 @@ func LockedOpenFile(path string, flag int, perm os.FileMode) (*LockedFile, error } } - return &LockedFile{File: f, size: st.Size()}, nil + return &LockedFile{File: f}, nil } func makeInheritSa() *syscall.SecurityAttributes { diff --git a/pkg/madmin/API.md b/pkg/madmin/API.md index 5d588db51..506690783 100644 --- a/pkg/madmin/API.md +++ b/pkg/madmin/API.md @@ -82,9 +82,9 @@ Fetch service status, replies disk space used, backend type and total disks offl | Param | Type | Description | |---|---|---| -|`backend.Type` | _BackendType_ | Type of backend used by the server currently only FS or XL. | -|`backend.OnlineDisks`| _int_ | Total number of disks online (only applies to XL backend), is empty for FS. | -|`backend.OfflineDisks` | _int_ | Total number of disks offline (only applies to XL backend), is empty for FS. | +|`backend.Type` | _BackendType_ | Type of backend used by the server currently only FS or Erasure. | +|`backend.OnlineDisks`| _int_ | Total number of disks online (only applies to Erasure backend), is empty for FS. | +|`backend.OfflineDisks` | _int_ | Total number of disks offline (only applies to Erasure backend), is empty for FS. | |`backend.ReadQuorum` | _int_ | Current total read quorum threshold before reads will be unavailable, is empty for FS. | |`backend.WriteQuorum` | _int_ | Current total write quorum threshold before writes will be unavailable, is empty for FS. | @@ -120,8 +120,8 @@ If successful restarts the running minio service, for distributed setup restarts ``` -### ListLocks(bucket, prefix string, olderThan time.Duration) ([]VolumeLockInfo, error) -If successful returns information on the list of locks held on ``bucket`` matching ``prefix`` older than ``olderThan`` seconds. +### ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) +If successful returns information on the list of locks held on ``bucket`` matching ``prefix`` for longer than ``duration`` seconds. __Example__ @@ -135,8 +135,8 @@ __Example__ ``` -### ClearLocks(bucket, prefix string, olderThan time.Duration) ([]VolumeLockInfo, error) -If successful returns information on the list of locks cleared on ``bucket`` matching ``prefix`` older than ``olderThan`` seconds. +### ClearLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) +If successful returns information on the list of locks cleared on ``bucket`` matching ``prefix`` for longer than ``duration`` seconds. __Example__ diff --git a/pkg/madmin/examples/lock-clear.go b/pkg/madmin/examples/lock-clear.go index 2f7a30de4..15fb2bfdf 100644 --- a/pkg/madmin/examples/lock-clear.go +++ b/pkg/madmin/examples/lock-clear.go @@ -37,7 +37,7 @@ func main() { log.Fatalln(err) } - // Clear locks held on mybucket/myprefix older than olderThan seconds. + // Clear locks held on mybucket/myprefix for longer than 30s. olderThan := time.Duration(30 * time.Second) locksCleared, err := madmClnt.ClearLocks("mybucket", "myprefix", olderThan) if err != nil { diff --git a/pkg/madmin/examples/lock-list.go b/pkg/madmin/examples/lock-list.go index bc1e9ff08..88023f4b4 100644 --- a/pkg/madmin/examples/lock-list.go +++ b/pkg/madmin/examples/lock-list.go @@ -37,7 +37,7 @@ func main() { log.Fatalln(err) } - // List locks held on mybucket/myprefix older than 30s. + // List locks held on mybucket/myprefix for longer than 30s. locksHeld, err := madmClnt.ListLocks("mybucket", "myprefix", time.Duration(30*time.Second)) if err != nil { log.Fatalln(err) diff --git a/pkg/madmin/heal-commands.go b/pkg/madmin/heal-commands.go index 34128345f..7544a8f89 100644 --- a/pkg/madmin/heal-commands.go +++ b/pkg/madmin/heal-commands.go @@ -19,7 +19,6 @@ package madmin import ( "encoding/xml" - "errors" "fmt" "net/http" "net/url" @@ -182,7 +181,7 @@ func mkHealQueryVal(bucket, prefix, marker, delimiter, maxKeyStr string) url.Val } // listObjectsHeal - issues heal list API request for a batch of maxKeys objects to be healed. -func (adm *AdminClient) listObjectsHeal(bucket, prefix, delimiter, marker string, maxKeys int) (listBucketHealResult, error) { +func (adm *AdminClient) listObjectsHeal(bucket, prefix, marker, delimiter string, maxKeys int) (listBucketHealResult, error) { // Construct query params. maxKeyStr := fmt.Sprintf("%d", maxKeys) queryVal := mkHealQueryVal(bucket, prefix, marker, delimiter, maxKeyStr) @@ -207,7 +206,8 @@ func (adm *AdminClient) listObjectsHeal(bucket, prefix, delimiter, marker string } if resp.StatusCode != http.StatusOK { - return toBeHealedObjects, errors.New("Got HTTP Status: " + resp.Status) + return toBeHealedObjects, httpRespToErrorResponse(resp) + } err = xml.NewDecoder(resp.Body).Decode(&toBeHealedObjects) @@ -309,7 +309,7 @@ func (adm *AdminClient) ListBucketsHeal() ([]BucketInfo, error) { } if resp.StatusCode != http.StatusOK { - return []BucketInfo{}, errors.New("Got HTTP Status: " + resp.Status) + return []BucketInfo{}, httpRespToErrorResponse(resp) } var listBucketsHealResult ListBucketsHealResponse @@ -364,7 +364,7 @@ func (adm *AdminClient) HealBucket(bucket string, dryrun bool) error { } if resp.StatusCode != http.StatusOK { - return errors.New("Got HTTP Status: " + resp.Status) + return httpRespToErrorResponse(resp) } return nil @@ -398,7 +398,7 @@ func (adm *AdminClient) HealObject(bucket, object string, dryrun bool) error { } if resp.StatusCode != http.StatusOK { - return errors.New("Got HTTP Status: " + resp.Status) + return httpRespToErrorResponse(resp) } return nil @@ -430,7 +430,7 @@ func (adm *AdminClient) HealFormat(dryrun bool) error { } if resp.StatusCode != http.StatusOK { - return errors.New("Got HTTP Status: " + resp.Status) + return httpRespToErrorResponse(resp) } return nil diff --git a/pkg/madmin/info-commands.go b/pkg/madmin/info-commands.go new file mode 100644 index 000000000..1c41fdf80 --- /dev/null +++ b/pkg/madmin/info-commands.go @@ -0,0 +1,119 @@ +/* + * Minio Cloud Storage, (C) 2017 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package madmin + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "time" +) + +// BackendType - represents different backend types. +type BackendType int + +// Enum for different backend types. +const ( + Unknown BackendType = iota + // Filesystem backend. + FS + // Multi disk Erasure (single, distributed) backend. + Erasure + + // Add your own backend. +) + +// StorageInfo - represents total capacity of underlying storage. +type StorageInfo struct { + // Total disk space. + Total int64 + // Free available disk space. + Free int64 + // Backend type. + Backend struct { + // Represents various backend types, currently on FS and Erasure. + Type BackendType + + // Following fields are only meaningful if BackendType is Erasure. + OnlineDisks int // Online disks during server startup. + OfflineDisks int // Offline disks during server startup. + ReadQuorum int // Minimum disks required for successful read operations. + WriteQuorum int // Minimum disks required for successful write operations. + } +} + +// ServerProperties holds some of the server's information such as uptime, +// version, region, .. +type ServerProperties struct { + Uptime time.Duration `json:"uptime"` + Version string `json:"version"` + CommitID string `json:"commitID"` + Region string `json:"region"` + SQSARN []string `json:"sqsARN"` +} + +// ServerConnStats holds network information +type ServerConnStats struct { + TotalInputBytes uint64 `json:"transferred"` + TotalOutputBytes uint64 `json:"received"` +} + +// ServerInfo holds the whole server information that will be +// returned by ServerInfo API. +type ServerInfo struct { + StorageInfo StorageInfo `json:"storage"` + ConnStats ServerConnStats `json:"network"` + Properties ServerProperties `json:"server"` +} + +// ServerInfo - Connect to a minio server and call Server Info Management API +// to fetch server's information represented by ServerInfo structure +func (adm *AdminClient) ServerInfo() (ServerInfo, error) { + // Prepare web service request + reqData := requestData{} + reqData.queryValues = make(url.Values) + reqData.queryValues.Set("info", "") + reqData.customHeaders = make(http.Header) + + resp, err := adm.executeMethod("GET", reqData) + defer closeResponse(resp) + if err != nil { + return ServerInfo{}, err + } + + // Check response http status code + if resp.StatusCode != http.StatusOK { + return ServerInfo{}, httpRespToErrorResponse(resp) + } + + // Unmarshal the server's json response + var info ServerInfo + + respBytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return ServerInfo{}, err + } + + err = json.Unmarshal(respBytes, &info) + if err != nil { + return ServerInfo{}, err + } + + return info, nil +} diff --git a/pkg/madmin/lock-commands.go b/pkg/madmin/lock-commands.go index 5b7e15cb9..3a3b44f56 100644 --- a/pkg/madmin/lock-commands.go +++ b/pkg/madmin/lock-commands.go @@ -19,7 +19,6 @@ package madmin import ( "encoding/json" - "errors" "io" "io/ioutil" "net/http" @@ -94,12 +93,12 @@ func getLockInfos(body io.Reader) ([]VolumeLockInfo, error) { // ListLocks - Calls List Locks Management API to fetch locks matching // bucket, prefix and held before the duration supplied. -func (adm *AdminClient) ListLocks(bucket, prefix string, olderThan time.Duration) ([]VolumeLockInfo, error) { +func (adm *AdminClient) ListLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) { queryVal := make(url.Values) queryVal.Set("lock", "") queryVal.Set("bucket", bucket) queryVal.Set("prefix", prefix) - queryVal.Set("older-than", olderThan.String()) + queryVal.Set("duration", duration.String()) hdrs := make(http.Header) hdrs.Set(minioAdminOpHeader, "list") @@ -118,7 +117,7 @@ func (adm *AdminClient) ListLocks(bucket, prefix string, olderThan time.Duration } if resp.StatusCode != http.StatusOK { - return nil, errors.New("Got HTTP Status: " + resp.Status) + return nil, httpRespToErrorResponse(resp) } return getLockInfos(resp.Body) @@ -126,12 +125,12 @@ func (adm *AdminClient) ListLocks(bucket, prefix string, olderThan time.Duration // ClearLocks - Calls Clear Locks Management API to clear locks held // on bucket, matching prefix older than duration supplied. -func (adm *AdminClient) ClearLocks(bucket, prefix string, olderThan time.Duration) ([]VolumeLockInfo, error) { +func (adm *AdminClient) ClearLocks(bucket, prefix string, duration time.Duration) ([]VolumeLockInfo, error) { queryVal := make(url.Values) queryVal.Set("lock", "") queryVal.Set("bucket", bucket) queryVal.Set("prefix", prefix) - queryVal.Set("older-than", olderThan.String()) + queryVal.Set("duration", duration.String()) hdrs := make(http.Header) hdrs.Set(minioAdminOpHeader, "clear") @@ -150,7 +149,7 @@ func (adm *AdminClient) ClearLocks(bucket, prefix string, olderThan time.Duratio } if resp.StatusCode != http.StatusOK { - return nil, errors.New("Got HTTP Status: " + resp.Status) + return nil, httpRespToErrorResponse(resp) } return getLockInfos(resp.Body) diff --git a/pkg/madmin/service.go b/pkg/madmin/service-commands.go similarity index 74% rename from pkg/madmin/service.go rename to pkg/madmin/service-commands.go index d5c732cb1..ee22a3feb 100644 --- a/pkg/madmin/service.go +++ b/pkg/madmin/service-commands.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2016 Minio, Inc. + * Minio Cloud Storage, (C) 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,51 +25,12 @@ import ( "io/ioutil" "net/http" "net/url" + "time" ) -// BackendType - represents different backend types. -type BackendType int - -// Enum for different backend types. -const ( - Unknown BackendType = iota - // Filesystem backend. - FS - // Multi disk XL (single, distributed) backend. - XL - - // Add your own backend. -) - -// StorageInfo - represents total capacity of underlying storage. -type StorageInfo struct { - // Total disk space. - Total int64 - // Free available disk space. - Free int64 - // Backend type. - Backend struct { - // Represents various backend types, currently on FS and XL. - Type BackendType - - // Following fields are only meaningful if BackendType is XL. - OnlineDisks int // Online disks during server startup. - OfflineDisks int // Offline disks during server startup. - ReadQuorum int // Minimum disks required for successful read operations. - WriteQuorum int // Minimum disks required for successful write operations. - } -} - -// ServerVersion - server version -type ServerVersion struct { - Version string `json:"version"` - CommitID string `json:"commitID"` -} - // ServiceStatusMetadata - contains the response of service status API type ServiceStatusMetadata struct { - StorageInfo StorageInfo `json:"storageInfo"` - ServerVersion ServerVersion `json:"serverVersion"` + Uptime time.Duration `json:"uptime"` } // ServiceStatus - Connect to a minio server and call Service Status Management API @@ -92,7 +53,7 @@ func (adm *AdminClient) ServiceStatus() (ServiceStatusMetadata, error) { // Check response http status code if resp.StatusCode != http.StatusOK { - return ServiceStatusMetadata{}, errors.New("Got HTTP Status: " + resp.Status) + return ServiceStatusMetadata{}, httpRespToErrorResponse(resp) } // Unmarshal the server's json response @@ -129,7 +90,7 @@ func (adm *AdminClient) ServiceRestart() error { } if resp.StatusCode != http.StatusOK { - return errors.New("Got HTTP Status: " + resp.Status) + return httpRespToErrorResponse(resp) } return nil } diff --git a/pkg/objcache/objcache.go b/pkg/objcache/objcache.go index 3a63a68de..d07a86214 100644 --- a/pkg/objcache/objcache.go +++ b/pkg/objcache/objcache.go @@ -217,7 +217,7 @@ func (c *Cache) Create(key string, size int64) (w io.WriteCloser, err error) { // returns an error ErrNotFoundInCache, if the key does not exist. // Returns ErrKeyNotFoundInCache if entry's lastAccessedTime is older // than objModTime. -func (c *Cache) Open(key string, objModTime time.Time) (io.ReadSeeker, error) { +func (c *Cache) Open(key string, objModTime time.Time) (io.ReaderAt, error) { // Entry exists, return the readable buffer. c.mutex.Lock() defer c.mutex.Unlock() diff --git a/pkg/objcache/objcache_test.go b/pkg/objcache/objcache_test.go index f1eed32d3..25cd1c69a 100644 --- a/pkg/objcache/objcache_test.go +++ b/pkg/objcache/objcache_test.go @@ -20,7 +20,6 @@ package objcache import ( "bytes" "io" - "io/ioutil" "testing" "time" ) @@ -173,7 +172,8 @@ func TestObjCache(t *testing.T) { t.Errorf("Test case 4 expected to pass, failed instead %s", err) } // Reads everything stored for key "test". - cbytes, err := ioutil.ReadAll(r) + cbytes := make([]byte, 5) + _, err = r.ReadAt(cbytes, 0) if err != nil { t.Errorf("Test case 4 expected to pass, failed instead %s", err) } diff --git a/cmd/trie.go b/pkg/trie/trie.go similarity index 58% rename from cmd/trie.go rename to pkg/trie/trie.go index fb84c3556..d32858c13 100644 --- a/cmd/trie.go +++ b/pkg/trie/trie.go @@ -1,5 +1,5 @@ /* - * Minio Cloud Storage, (C) 2015 Minio, Inc. + * Minio Cloud Storage, (C) 2014, 2015, 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,80 +14,78 @@ * limitations under the License. */ -package cmd +// Package trie implements a simple trie tree for minio server/tools borrows +// idea from - https://godoc.org/golang.org/x/text/internal/triegen. +package trie -// This package borrows idea from - https://godoc.org/golang.org/x/text/internal/triegen +// Node trie tree node container carries value and children. +type Node struct { + exists bool + value interface{} + child map[rune]*Node // runes as child. +} -// Trie trie container +// newNode create a new trie node. +func newNode() *Node { + return &Node{ + exists: false, + value: nil, + child: make(map[rune]*Node), + } +} + +// Trie is a trie container. type Trie struct { - root *trieNode + root *Node size int } -// newTrie get new trie -func newTrie() *Trie { - return &Trie{ - root: newTrieNode(), - size: 0, - } +// Root returns root node. +func (t *Trie) Root() *Node { + return t.root } -// trieNode trie tree node container carries value and children -type trieNode struct { - exists bool - value interface{} - child map[rune]*trieNode // runes as child -} - -func newTrieNode() *trieNode { - return &trieNode{ - exists: false, - value: nil, - child: make(map[rune]*trieNode), - } -} - -// Insert insert a key +// Insert insert a key. func (t *Trie) Insert(key string) { curNode := t.root for _, v := range key { if curNode.child[v] == nil { - curNode.child[v] = newTrieNode() + curNode.child[v] = newNode() } curNode = curNode.child[v] } if !curNode.exists { - // increment when new rune child is added + // increment when new rune child is added. t.size++ curNode.exists = true } - // value is stored for retrieval in future + // value is stored for retrieval in future. curNode.value = key } -// PrefixMatch - prefix match +// PrefixMatch - prefix match. func (t *Trie) PrefixMatch(key string) []interface{} { node, _ := t.findNode(key) if node != nil { - return t.walk(node) + return t.Walk(node) } return []interface{}{} } -// walk the tree -func (t *Trie) walk(node *trieNode) (ret []interface{}) { +// Walk the tree. +func (t *Trie) Walk(node *Node) (ret []interface{}) { if node.exists { ret = append(ret, node.value) } for _, v := range node.child { - ret = append(ret, t.walk(v)...) + ret = append(ret, t.Walk(v)...) } return } -// find nodes corresponding to key -func (t *Trie) findNode(key string) (node *trieNode, index int) { +// find nodes corresponding to key. +func (t *Trie) findNode(key string) (node *Node, index int) { curNode := t.root f := false for k, v := range key { @@ -110,3 +108,11 @@ func (t *Trie) findNode(key string) (node *trieNode, index int) { return curNode, index } + +// NewTrie create a new trie. +func NewTrie() *Trie { + return &Trie{ + root: newNode(), + size: 0, + } +} diff --git a/cmd/trie_test.go b/pkg/trie/trie_test.go similarity index 89% rename from cmd/trie_test.go rename to pkg/trie/trie_test.go index b37093144..454b898e0 100644 --- a/cmd/trie_test.go +++ b/pkg/trie/trie_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package cmd +package trie import ( "testing" @@ -23,7 +23,7 @@ import ( // Simply make sure creating a new tree works. func TestNewTrie(t *testing.T) { var trie *Trie - trie = newTrie() + trie = NewTrie() if trie.size != 0 { t.Errorf("expected size 0, got: %d", trie.size) @@ -33,7 +33,7 @@ func TestNewTrie(t *testing.T) { // Ensure that we can insert new keys into the tree, then check the size. func TestInsert(t *testing.T) { var trie *Trie - trie = newTrie() + trie = NewTrie() // We need to have an empty tree to begin with. if trie.size != 0 { @@ -52,10 +52,10 @@ func TestInsert(t *testing.T) { // Ensure that PrefixMatch gives us the correct two keys in the tree. func TestPrefixMatch(t *testing.T) { var trie *Trie - trie = newTrie() + trie = NewTrie() // Feed it some fodder: only 'minio' and 'miny-os' should trip the matcher. - trie.Insert(globalMinioDefaultOwnerID) + trie.Insert("minio") trie.Insert("amazon") trie.Insert("cheerio") trie.Insert("miny-o's") @@ -65,7 +65,7 @@ func TestPrefixMatch(t *testing.T) { t.Errorf("expected two matches, got: %d", len(matches)) } - if matches[0] != globalMinioDefaultOwnerID && matches[1] != globalMinioDefaultOwnerID { + if matches[0] != "minio" && matches[1] != "minio" { t.Errorf("expected one match to be 'minio', got: '%s' and '%s'", matches[0], matches[1]) } } diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md index 0921f98a5..25abbca3f 100644 --- a/vendor/github.com/fatih/color/README.md +++ b/vendor/github.com/fatih/color/README.md @@ -56,6 +56,16 @@ whiteBackground := red.Add(color.BgWhite) whiteBackground.Println("Red text with white background.") ``` +### Use your own output (io.Writer) + +```go +// Use your own io.Writer output +color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + +blue := color.New(color.FgBlue) +blue.Fprint(writer, "This will print text in blue.") +``` + ### Custom print functions (PrintFunc) ```go @@ -69,6 +79,17 @@ notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() notice("Don't forget this...") ``` +### Custom fprint functions (FprintFunc) + +```go +blue := color.New(FgBlue).FprintfFunc() +blue(myWriter, "important notice: %s", stars) + +// Mix up with multiple attributes +success := color.New(color.Bold, color.FgGreen).FprintlnFunc() +success(myWriter, "Don't forget this...") +``` + ### Insert into noncolor strings (SprintFunc) ```go @@ -81,8 +102,8 @@ info := color.New(color.FgWhite, color.BgGreen).SprintFunc() fmt.Printf("This %s rocks!\n", info("package")) // Use helper functions -fmt.Printf("This", color.RedString("warning"), "should be not neglected.") -fmt.Printf(color.GreenString("Info:"), "an important message." ) +fmt.Println("This", color.RedString("warning"), "should be not neglected.") +fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.") // Windows supported too! Just don't forget to change the output to color.Output fmt.Fprintf(color.Output, "Windows support: %s", color.GreenString("PASS")) diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index e3e997284..dba8f211e 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -2,19 +2,32 @@ package color import ( "fmt" + "io" "os" "strconv" "strings" + "sync" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" ) -// NoColor defines if the output is colorized or not. It's dynamically set to -// false or true based on the stdout's file descriptor referring to a terminal -// or not. This is a global option and affects all colors. For more control -// over each color block use the methods DisableColor() individually. -var NoColor = !isatty.IsTerminal(os.Stdout.Fd()) +var ( + // NoColor defines if the output is colorized or not. It's dynamically set to + // false or true based on the stdout's file descriptor referring to a terminal + // or not. This is a global option and affects all colors. For more control + // over each color block use the methods DisableColor() individually. + NoColor = !isatty.IsTerminal(os.Stdout.Fd()) || os.Getenv("TERM") == "dumb" + + // Output defines the standard output of the print functions. By default + // os.Stdout is used. + Output = colorable.NewColorableStdout() + + // colorsCache is used to reduce the count of created Color objects and + // allows to reuse already created objects with required Attribute. + colorsCache = make(map[Attribute]*Color) + colorsCacheMu sync.Mutex // protects colorsCache +) // Color defines a custom color object which is defined by SGR parameters. type Color struct { @@ -132,6 +145,27 @@ func (c *Color) unset() { Unset() } +func (c *Color) setWriter(w io.Writer) *Color { + if c.isNoColorSet() { + return c + } + + fmt.Fprintf(w, c.format()) + return c +} + +func (c *Color) unsetWriter(w io.Writer) { + if c.isNoColorSet() { + return + } + + if NoColor { + return + } + + fmt.Fprintf(w, "%s[%dm", escape, Reset) +} + // Add is used to chain SGR parameters. Use as many as parameters to combine // and create custom color objects. Example: Add(color.FgRed, color.Underline). func (c *Color) Add(value ...Attribute) *Color { @@ -145,9 +179,17 @@ func (c *Color) prepend(value Attribute) { c.params[0] = value } -// Output defines the standard output of the print functions. By default -// os.Stdout is used. -var Output = colorable.NewColorableStdout() +// Fprint formats using the default formats for its operands and writes to w. +// Spaces are added between operands when neither is a string. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprint(w, a...) +} // Print formats using the default formats for its operands and writes to // standard output. Spaces are added between operands when neither is a @@ -161,6 +203,17 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { return fmt.Fprint(Output, a...) } +// Fprintf formats according to a format specifier and writes to w. +// It returns the number of bytes written and any write error encountered. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintf(w, format, a...) +} + // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. // This is the standard fmt.Printf() method wrapped with the given color. @@ -171,6 +224,17 @@ func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { return fmt.Fprintf(Output, format, a...) } +// Fprintln formats using the default formats for its operands and writes to w. +// Spaces are always added between operands and a newline is appended. +// On Windows, users should wrap w with colorable.NewColorable() if w is of +// type *os.File. +func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + c.setWriter(w) + defer c.unsetWriter(w) + + return fmt.Fprintln(w, a...) +} + // Println formats using the default formats for its operands and writes to // standard output. Spaces are always added between operands and a newline is // appended. It returns the number of bytes written and any write error @@ -183,27 +247,57 @@ func (c *Color) Println(a ...interface{}) (n int, err error) { return fmt.Fprintln(Output, a...) } +// FprintFunc returns a new function that prints the passed arguments as +// colorized with color.Fprint(). +func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprint(w, a...) + } +} + // PrintFunc returns a new function that prints the passed arguments as // colorized with color.Print(). func (c *Color) PrintFunc() func(a ...interface{}) { - return func(a ...interface{}) { c.Print(a...) } + return func(a ...interface{}) { + c.Print(a...) + } +} + +// FprintfFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintf(). +func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { + return func(w io.Writer, format string, a ...interface{}) { + c.Fprintf(w, format, a...) + } } // PrintfFunc returns a new function that prints the passed arguments as // colorized with color.Printf(). func (c *Color) PrintfFunc() func(format string, a ...interface{}) { - return func(format string, a ...interface{}) { c.Printf(format, a...) } + return func(format string, a ...interface{}) { + c.Printf(format, a...) + } +} + +// FprintlnFunc returns a new function that prints the passed arguments as +// colorized with color.Fprintln(). +func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { + return func(w io.Writer, a ...interface{}) { + c.Fprintln(w, a...) + } } // PrintlnFunc returns a new function that prints the passed arguments as // colorized with color.Println(). func (c *Color) PrintlnFunc() func(a ...interface{}) { - return func(a ...interface{}) { c.Println(a...) } + return func(a ...interface{}) { + c.Println(a...) + } } // SprintFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprint(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output, example: +// string. Windows users should use this in conjunction with color.Output, example: // // put := New(FgYellow).SprintFunc() // fmt.Fprintf(color.Output, "This is a %s", put("warning")) @@ -215,7 +309,7 @@ func (c *Color) SprintFunc() func(a ...interface{}) string { // SprintfFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprintf(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output. +// string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { return func(format string, a ...interface{}) string { return c.wrap(fmt.Sprintf(format, a...)) @@ -224,7 +318,7 @@ func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { // SprintlnFunc returns a new function that returns colorized strings for the // given arguments with fmt.Sprintln(). Useful to put into or mix into other -// string. Windows users should use this in conjuction with color.Output. +// string. Windows users should use this in conjunction with color.Output. func (c *Color) SprintlnFunc() func(a ...interface{}) string { return func(a ...interface{}) string { return c.wrap(fmt.Sprintln(a...)) @@ -267,7 +361,7 @@ func (c *Color) DisableColor() { c.noColor = boolPtr(true) } -// EnableColor enables the color output. Use it in conjuction with +// EnableColor enables the color output. Use it in conjunction with // DisableColor(). Otherwise this method has no side effects. func (c *Color) EnableColor() { c.noColor = boolPtr(false) @@ -312,91 +406,105 @@ func boolPtr(v bool) *bool { return &v } -// Black is an convenient helper function to print with black foreground. A -// newline is appended to format by default. -func Black(format string, a ...interface{}) { printColor(format, FgBlack, a...) } +func getCachedColor(p Attribute) *Color { + colorsCacheMu.Lock() + defer colorsCacheMu.Unlock() -// Red is an convenient helper function to print with red foreground. A -// newline is appended to format by default. -func Red(format string, a ...interface{}) { printColor(format, FgRed, a...) } + c, ok := colorsCache[p] + if !ok { + c = New(p) + colorsCache[p] = c + } -// Green is an convenient helper function to print with green foreground. A -// newline is appended to format by default. -func Green(format string, a ...interface{}) { printColor(format, FgGreen, a...) } + return c +} -// Yellow is an convenient helper function to print with yellow foreground. -// A newline is appended to format by default. -func Yellow(format string, a ...interface{}) { printColor(format, FgYellow, a...) } +func colorPrint(format string, p Attribute, a ...interface{}) { + c := getCachedColor(p) -// Blue is an convenient helper function to print with blue foreground. A -// newline is appended to format by default. -func Blue(format string, a ...interface{}) { printColor(format, FgBlue, a...) } - -// Magenta is an convenient helper function to print with magenta foreground. -// A newline is appended to format by default. -func Magenta(format string, a ...interface{}) { printColor(format, FgMagenta, a...) } - -// Cyan is an convenient helper function to print with cyan foreground. A -// newline is appended to format by default. -func Cyan(format string, a ...interface{}) { printColor(format, FgCyan, a...) } - -// White is an convenient helper function to print with white foreground. A -// newline is appended to format by default. -func White(format string, a ...interface{}) { printColor(format, FgWhite, a...) } - -func printColor(format string, p Attribute, a ...interface{}) { if !strings.HasSuffix(format, "\n") { format += "\n" } - c := &Color{params: []Attribute{p}} - c.Printf(format, a...) + if len(a) == 0 { + c.Print(format) + } else { + c.Printf(format, a...) + } } +func colorString(format string, p Attribute, a ...interface{}) string { + c := getCachedColor(p) + + if len(a) == 0 { + return c.SprintFunc()(format) + } + + return c.SprintfFunc()(format, a...) +} + +// Black is an convenient helper function to print with black foreground. A +// newline is appended to format by default. +func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } + +// Red is an convenient helper function to print with red foreground. A +// newline is appended to format by default. +func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } + +// Green is an convenient helper function to print with green foreground. A +// newline is appended to format by default. +func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } + +// Yellow is an convenient helper function to print with yellow foreground. +// A newline is appended to format by default. +func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } + +// Blue is an convenient helper function to print with blue foreground. A +// newline is appended to format by default. +func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } + +// Magenta is an convenient helper function to print with magenta foreground. +// A newline is appended to format by default. +func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } + +// Cyan is an convenient helper function to print with cyan foreground. A +// newline is appended to format by default. +func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } + +// White is an convenient helper function to print with white foreground. A +// newline is appended to format by default. +func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } + // BlackString is an convenient helper function to return a string with black // foreground. -func BlackString(format string, a ...interface{}) string { - return New(FgBlack).SprintfFunc()(format, a...) -} +func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } // RedString is an convenient helper function to return a string with red // foreground. -func RedString(format string, a ...interface{}) string { - return New(FgRed).SprintfFunc()(format, a...) -} +func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } // GreenString is an convenient helper function to return a string with green // foreground. -func GreenString(format string, a ...interface{}) string { - return New(FgGreen).SprintfFunc()(format, a...) -} +func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } // YellowString is an convenient helper function to return a string with yellow // foreground. -func YellowString(format string, a ...interface{}) string { - return New(FgYellow).SprintfFunc()(format, a...) -} +func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } // BlueString is an convenient helper function to return a string with blue // foreground. -func BlueString(format string, a ...interface{}) string { - return New(FgBlue).SprintfFunc()(format, a...) -} +func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } // MagentaString is an convenient helper function to return a string with magenta // foreground. func MagentaString(format string, a ...interface{}) string { - return New(FgMagenta).SprintfFunc()(format, a...) + return colorString(format, FgMagenta, a...) } // CyanString is an convenient helper function to return a string with cyan // foreground. -func CyanString(format string, a ...interface{}) string { - return New(FgCyan).SprintfFunc()(format, a...) -} +func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } // WhiteString is an convenient helper function to return a string with white // foreground. -func WhiteString(format string, a ...interface{}) string { - return New(FgWhite).SprintfFunc()(format, a...) -} +func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index 17908787c..1e57812d7 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -37,6 +37,11 @@ separate color object. whiteBackground := red.Add(color.BgWhite) whiteBackground.Println("Red text with White background.") + // Use your own io.Writer output + color.New(color.FgBlue).Fprintln(myWriter, "blue color!") + + blue := color.New(color.FgBlue) + blue.Fprint(myWriter, "This will print text in blue.") You can create PrintXxx functions to simplify even more: @@ -49,6 +54,15 @@ You can create PrintXxx functions to simplify even more: notice := color.New(color.Bold, color.FgGreen).PrintlnFunc() notice("don't forget this...") +You can also FprintXxx functions to pass your own io.Writer: + + blue := color.New(FgBlue).FprintfFunc() + blue(myWriter, "important notice: %s", stars) + + // Mix up with multiple attributes + success := color.New(color.Bold, color.FgGreen).FprintlnFunc() + success(myWriter, don't forget this...") + Or create SprintXxx functions to mix strings with other non-colorized strings: diff --git a/vendor/github.com/mattn/go-isatty/isatty_appengine.go b/vendor/github.com/mattn/go-isatty/isatty_appengine.go new file mode 100644 index 000000000..83c588773 --- /dev/null +++ b/vendor/github.com/mattn/go-isatty/isatty_appengine.go @@ -0,0 +1,9 @@ +// +build appengine + +package isatty + +// IsTerminal returns true if the file descriptor is terminal which +// is always false on on appengine classic which is a sandboxed PaaS. +func IsTerminal(fd uintptr) bool { + return false +} diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go index 98ffe86a4..42f2514d1 100644 --- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go +++ b/vendor/github.com/mattn/go-isatty/isatty_bsd.go @@ -1,4 +1,4 @@ -// +build darwin freebsd openbsd netbsd +// +build darwin freebsd openbsd netbsd dragonfly // +build !appengine package isatty diff --git a/vendor/github.com/minio/blake2b-simd/blake2b.go b/vendor/github.com/minio/blake2b-simd/blake2b.go deleted file mode 100644 index 538466a1a..000000000 --- a/vendor/github.com/minio/blake2b-simd/blake2b.go +++ /dev/null @@ -1,301 +0,0 @@ -// Written in 2012 by Dmitry Chestnykh. -// -// To the extent possible under law, the author have dedicated all copyright -// and related and neighboring rights to this software to the public domain -// worldwide. This software is distributed without any warranty. -// http://creativecommons.org/publicdomain/zero/1.0/ - -// Package blake2b implements BLAKE2b cryptographic hash function. -package blake2b - -import ( - "encoding/binary" - "errors" - "hash" -) - -const ( - BlockSize = 128 // block size of algorithm - Size = 64 // maximum digest size - SaltSize = 16 // maximum salt size - PersonSize = 16 // maximum personalization string size - KeySize = 64 // maximum size of key -) - -type digest struct { - h [8]uint64 // current chain value - t [2]uint64 // message bytes counter - f [2]uint64 // finalization flags - x [BlockSize]byte // buffer for data not yet compressed - nx int // number of bytes in buffer - - ih [8]uint64 // initial chain value (after config) - paddedKey [BlockSize]byte // copy of key, padded with zeros - isKeyed bool // indicates whether hash was keyed - size uint8 // digest size in bytes - isLastNode bool // indicates processing of the last node in tree hashing -} - -// Initialization values. -var iv = [8]uint64{ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, - 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, - 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, -} - -// Config is used to configure hash function parameters and keying. -// All parameters are optional. -type Config struct { - Size uint8 // digest size (if zero, default size of 64 bytes is used) - Key []byte // key for prefix-MAC - Salt []byte // salt (if < 16 bytes, padded with zeros) - Person []byte // personalization (if < 16 bytes, padded with zeros) - Tree *Tree // parameters for tree hashing -} - -// Tree represents parameters for tree hashing. -type Tree struct { - Fanout uint8 // fanout - MaxDepth uint8 // maximal depth - LeafSize uint32 // leaf maximal byte length (0 for unlimited) - NodeOffset uint64 // node offset (0 for first, leftmost or leaf) - NodeDepth uint8 // node depth (0 for leaves) - InnerHashSize uint8 // inner hash byte length - IsLastNode bool // indicates processing of the last node of layer -} - -var ( - defaultConfig = &Config{Size: Size} - config256 = &Config{Size: 32} -) - -func verifyConfig(c *Config) error { - if c.Size > Size { - return errors.New("digest size is too large") - } - if len(c.Key) > KeySize { - return errors.New("key is too large") - } - if len(c.Salt) > SaltSize { - // Smaller salt is okay: it will be padded with zeros. - return errors.New("salt is too large") - } - if len(c.Person) > PersonSize { - // Smaller personalization is okay: it will be padded with zeros. - return errors.New("personalization is too large") - } - if c.Tree != nil { - if c.Tree.Fanout == 1 { - return errors.New("fanout of 1 is not allowed in tree mode") - } - if c.Tree.MaxDepth < 2 { - return errors.New("incorrect tree depth") - } - if c.Tree.InnerHashSize < 1 || c.Tree.InnerHashSize > Size { - return errors.New("incorrect tree inner hash size") - } - } - return nil -} - -// New returns a new hash.Hash configured with the given Config. -// Config can be nil, in which case the default one is used, calculating 64-byte digest. -// Returns non-nil error if Config contains invalid parameters. -func New(c *Config) (hash.Hash, error) { - if c == nil { - c = defaultConfig - } else { - if c.Size == 0 { - // Set default size if it's zero. - c.Size = Size - } - if err := verifyConfig(c); err != nil { - return nil, err - } - } - d := new(digest) - d.initialize(c) - return d, nil -} - -// initialize initializes digest with the given -// config, which must be non-nil and verified. -func (d *digest) initialize(c *Config) { - // Create parameter block. - var p [BlockSize]byte - p[0] = c.Size - p[1] = uint8(len(c.Key)) - if c.Salt != nil { - copy(p[32:], c.Salt) - } - if c.Person != nil { - copy(p[48:], c.Person) - } - if c.Tree != nil { - p[2] = c.Tree.Fanout - p[3] = c.Tree.MaxDepth - binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize) - binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset) - p[16] = c.Tree.NodeDepth - p[17] = c.Tree.InnerHashSize - } else { - p[2] = 1 - p[3] = 1 - } - - // Initialize. - d.size = c.Size - for i := 0; i < 8; i++ { - d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:]) - } - if c.Tree != nil && c.Tree.IsLastNode { - d.isLastNode = true - } - - // Process key. - if c.Key != nil { - copy(d.paddedKey[:], c.Key) - d.Write(d.paddedKey[:]) - d.isKeyed = true - } - // Save a copy of initialized state. - copy(d.ih[:], d.h[:]) -} - -// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum. -func New512() hash.Hash { - d := new(digest) - d.initialize(defaultConfig) - return d -} - -// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum. -func New256() hash.Hash { - d := new(digest) - d.initialize(config256) - return d -} - -// NewMAC returns a new hash.Hash computing BLAKE2b prefix- -// Message Authentication Code of the given size in bytes -// (up to 64) with the given key (up to 64 bytes in length). -func NewMAC(outBytes uint8, key []byte) hash.Hash { - d, err := New(&Config{Size: outBytes, Key: key}) - if err != nil { - panic(err.Error()) - } - return d -} - -// Reset resets the state of digest to the initial state -// after configuration and keying. -func (d *digest) Reset() { - copy(d.h[:], d.ih[:]) - d.t[0] = 0 - d.t[1] = 0 - d.f[0] = 0 - d.f[1] = 0 - d.nx = 0 - if d.isKeyed { - d.Write(d.paddedKey[:]) - } -} - -// Size returns the digest size in bytes. -func (d *digest) Size() int { return int(d.size) } - -// BlockSize returns the algorithm block size in bytes. -func (d *digest) BlockSize() int { return BlockSize } - -func (d *digest) Write(p []byte) (nn int, err error) { - nn = len(p) - left := BlockSize - d.nx - if len(p) > left { - // Process buffer. - copy(d.x[d.nx:], p[:left]) - p = p[left:] - compress(d, d.x[:]) - d.nx = 0 - } - // Process full blocks except for the last one. - if len(p) > BlockSize { - n := len(p) &^ (BlockSize - 1) - if n == len(p) { - n -= BlockSize - } - compress(d, p[:n]) - p = p[n:] - } - // Fill buffer. - d.nx += copy(d.x[d.nx:], p) - return -} - -// Sum returns the calculated checksum. -func (d *digest) Sum(in []byte) []byte { - // Make a copy of d so that caller can keep writing and summing. - d0 := *d - hash := d0.checkSum() - return append(in, hash[:d0.size]...) -} - -func (d *digest) checkSum() [Size]byte { - // Do not create unnecessary copies of the key. - if d.isKeyed { - for i := 0; i < len(d.paddedKey); i++ { - d.paddedKey[i] = 0 - } - } - - dec := BlockSize - uint64(d.nx) - if d.t[0] < dec { - d.t[1]-- - } - d.t[0] -= dec - - // Pad buffer with zeros. - for i := d.nx; i < len(d.x); i++ { - d.x[i] = 0 - } - // Set last block flag. - d.f[0] = 0xffffffffffffffff - if d.isLastNode { - d.f[1] = 0xffffffffffffffff - } - // Compress last block. - compress(d, d.x[:]) - - var out [Size]byte - j := 0 - for _, s := range d.h[:(d.size-1)/8+1] { - out[j+0] = byte(s >> 0) - out[j+1] = byte(s >> 8) - out[j+2] = byte(s >> 16) - out[j+3] = byte(s >> 24) - out[j+4] = byte(s >> 32) - out[j+5] = byte(s >> 40) - out[j+6] = byte(s >> 48) - out[j+7] = byte(s >> 56) - j += 8 - } - return out -} - -// Sum512 returns a 64-byte BLAKE2b hash of data. -func Sum512(data []byte) [64]byte { - var d digest - d.initialize(defaultConfig) - d.Write(data) - return d.checkSum() -} - -// Sum256 returns a 32-byte BLAKE2b hash of data. -func Sum256(data []byte) (out [32]byte) { - var d digest - d.initialize(config256) - d.Write(data) - sum := d.checkSum() - copy(out[:], sum[:32]) - return -} diff --git a/vendor/github.com/minio/blake2b-simd/compressAvx2_amd64.go b/vendor/github.com/minio/blake2b-simd/compressAvx2_amd64.go deleted file mode 100644 index ec53599f8..000000000 --- a/vendor/github.com/minio/blake2b-simd/compressAvx2_amd64.go +++ /dev/null @@ -1,47 +0,0 @@ -//+build !noasm -//+build !appengine - -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package blake2b - -//go:noescape -func compressAVX2Loop(p []uint8, in, iv, t, f, shffle, out []uint64) - -func compressAVX2(d *digest, p []uint8) { - var ( - in [8]uint64 - out [8]uint64 - shffle [8]uint64 - ) - - // vector for PSHUFB instruction - shffle[0] = 0x0201000706050403 - shffle[1] = 0x0a09080f0e0d0c0b - shffle[2] = 0x0201000706050403 - shffle[3] = 0x0a09080f0e0d0c0b - shffle[4] = 0x0100070605040302 - shffle[5] = 0x09080f0e0d0c0b0a - shffle[6] = 0x0100070605040302 - shffle[7] = 0x09080f0e0d0c0b0a - - in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7] = d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] - - compressAVX2Loop(p, in[:], iv[:], d.t[:], d.f[:], shffle[:], out[:]) - - d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7] -} diff --git a/vendor/github.com/minio/blake2b-simd/compressAvx2_amd64.s b/vendor/github.com/minio/blake2b-simd/compressAvx2_amd64.s deleted file mode 100644 index 24df234b5..000000000 --- a/vendor/github.com/minio/blake2b-simd/compressAvx2_amd64.s +++ /dev/null @@ -1,671 +0,0 @@ -//+build !noasm !appengine - -// -// Minio Cloud Storage, (C) 2016 Minio, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// -// Based on AVX2 implementation from https://github.com/sneves/blake2-avx2/blob/master/blake2b-common.h -// -// Use github.com/fwessels/asm2plan9s on this file to assemble instructions to their Plan9 equivalent -// -// Assembly code below essentially follows the ROUND macro (see blake2b-round.h) which is defined as: -// #define ROUND(r) \ -// LOAD_MSG_ ##r ##_1(b0, b1); \ -// G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// LOAD_MSG_ ##r ##_2(b0, b1); \ -// G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ -// LOAD_MSG_ ##r ##_3(b0, b1); \ -// G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// LOAD_MSG_ ##r ##_4(b0, b1); \ -// G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); -// -// as well as the go equivalent in https://github.com/dchest/blake2b/blob/master/block.go -// -// As in the macro, G1/G2 in the 1st and 2nd half are identical (so literal copy of assembly) -// -// Rounds are also the same, except for the loading of the message (and rounds 1 & 11 and -// rounds 2 & 12 are identical) -// - -#define G1 \ - \ // G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); - BYTE $0xc5; BYTE $0xfd; BYTE $0xd4; BYTE $0xc4 \ // VPADDQ YMM0,YMM0,YMM4 /* v0 += m[0], v1 += m[2], v2 += m[4], v3 += m[6] */ - BYTE $0xc5; BYTE $0xfd; BYTE $0xd4; BYTE $0xc1 \ // VPADDQ YMM0,YMM0,YMM1 /* v0 += v4, v1 += v5, v2 += v6, v3 += v7 */ - BYTE $0xc5; BYTE $0xe5; BYTE $0xef; BYTE $0xd8 \ // VPXOR YMM3,YMM3,YMM0 /* v12 ^= v0, v13 ^= v1, v14 ^= v2, v15 ^= v3 */ - BYTE $0xc5; BYTE $0xfd; BYTE $0x70; BYTE $0xdb; BYTE $0xb1 \ // VPSHUFD YMM3,YMM3,0xb1 /* v12 = v12<<(64-32) | v12>>32, v13 = */ - BYTE $0xc5; BYTE $0xed; BYTE $0xd4; BYTE $0xd3 \ // VPADDQ YMM2,YMM2,YMM3 /* v8 += v12, v9 += v13, v10 += v14, v11 += v15 */ - BYTE $0xc5; BYTE $0xf5; BYTE $0xef; BYTE $0xca \ // VPXOR YMM1,YMM1,YMM2 /* v4 ^= v8, v5 ^= v9, v6 ^= v10, v7 ^= v11 */ - BYTE $0xc4; BYTE $0xe2; BYTE $0x75; BYTE $0x00; BYTE $0xce // VPSHUFB YMM1,YMM1,YMM6 /* v4 = v4<<(64-24) | v4>>24, ..., ..., v7 = v7<<(64-24) | v7>>24 */ - -#define G2 \ - BYTE $0xc5; BYTE $0xfd; BYTE $0xd4; BYTE $0xc5 \ // VPADDQ YMM0,YMM0,YMM5 /* v0 += m[1], v1 += m[3], v2 += m[5], v3 += m[7] */ - BYTE $0xc5; BYTE $0xfd; BYTE $0xd4; BYTE $0xc1 \ // VPADDQ YMM0,YMM0,YMM1 /* v0 += v4, v1 += v5, v2 += v6, v3 += v7 */ - BYTE $0xc5; BYTE $0xe5; BYTE $0xef; BYTE $0xd8 \ // VPXOR YMM3,YMM3,YMM0 /* v12 ^= v0, v13 ^= v1, v14 ^= v2, v15 ^= v3 */ - BYTE $0xc4; BYTE $0xe2; BYTE $0x65; BYTE $0x00; BYTE $0xdf \ // VPSHUFB YMM3,YMM3,YMM7 /* v12 = v12<<(64-16) | v12>>16, ..., ..., v15 = v15<<(64-16) | v15>>16 */ - BYTE $0xc5; BYTE $0xed; BYTE $0xd4; BYTE $0xd3 \ // VPADDQ YMM2,YMM2,YMM3 /* v8 += v12, v9 += v13, v10 += v14, v11 += v15 */ - BYTE $0xc5; BYTE $0xf5; BYTE $0xef; BYTE $0xca \ // VPXOR YMM1,YMM1,YMM2 /* v4 ^= v8, v5 ^= v9, v6 ^= v10, v7 ^= v11 */ - BYTE $0xc5; BYTE $0x75; BYTE $0xd4; BYTE $0xf9 \ // VPADDQ YMM15,YMM1,YMM1 /* temp reg = reg*2 */ - BYTE $0xc5; BYTE $0xf5; BYTE $0x73; BYTE $0xd1; BYTE $0x3f \ // VPSRLQ YMM1,YMM1,0x3f /* reg = reg>>63 */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x75; BYTE $0xef; BYTE $0xcf // VPXOR YMM1,YMM1,YMM15 /* ORed together: v4 = v4<<(64-63) | v4>>63, v5 = v5<<(64-63) | v5>>63 */ - -#define DIAGONALIZE \ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb \ // VPERMQ YMM3, YMM3, 0x93 - BYTE $0x93 \ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2 \ // VPERMQ YMM2, YMM2, 0x4e - BYTE $0x4e \ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 \ // VPERMQ YMM1, YMM1, 0x39 - BYTE $0x39 \ - // DO NOT DELETE -- macro delimiter (previous line extended) - -#define UNDIAGONALIZE \ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb \ // VPERMQ YMM3, YMM3, 0x39 - BYTE $0x39 \ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2 \ // VPERMQ YMM2, YMM2, 0x4e - BYTE $0x4e \ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 \ // VPERMQ YMM1, YMM1, 0x93 - BYTE $0x93 \ - // DO NOT DELETE -- macro delimiter (previous line extended) - -#define LOAD_SHUFFLE \ - MOVQ shffle+120(FP), SI \ // SI: &shuffle - BYTE $0xc5; BYTE $0xfe; BYTE $0x6f; BYTE $0x36 \ // VMOVDQU YMM6, [rsi] - BYTE $0xc5; BYTE $0xfe; BYTE $0x6f; BYTE $0x7e; BYTE $0x20 // VMOVDQU YMM7, 32[rsi] - -// func compressAVX2Loop(compressSSE(p []uint8, in, iv, t, f, shffle, out []uint64) -TEXT ·compressAVX2Loop(SB), 7, $0 - - // REGISTER USE - // Y0 - Y3: v0 - v15 - // Y4 - Y5: m[0] - m[7] - // Y6 - Y7: shuffle value - // Y8 - Y9: temp registers - // Y10 -Y13: copy of full message - // Y15: temp register - - // Load digest - MOVQ in+24(FP), SI // SI: &in - BYTE $0xc5; BYTE $0xfe; BYTE $0x6f; BYTE $0x06 // VMOVDQU YMM0, [rsi] - BYTE $0xc5; BYTE $0xfe; BYTE $0x6f; BYTE $0x4e; BYTE $0x20 // VMOVDQU YMM1, 32[rsi] - - // Already store digest into &out (so we can reload it later generically) - MOVQ out+144(FP), SI // SI: &out - BYTE $0xc5; BYTE $0xfe; BYTE $0x7f; BYTE $0x06 // VMOVDQU [rsi], YMM0 - BYTE $0xc5; BYTE $0xfe; BYTE $0x7f; BYTE $0x4e; BYTE $0x20 // VMOVDQU 32[rsi], YMM1 - - // Initialize message pointer and loop counter - MOVQ message+0(FP), DX // DX: &p (message) - MOVQ message_len+8(FP), R8 // R8: len(message) - SHRQ $7, R8 // len(message) / 128 - CMPQ R8, $0 - JEQ complete - -loop: - // Increment counter - MOVQ t+72(FP), SI // SI: &t - MOVQ 0(SI), R9 // - ADDQ $128, R9 // /* d.t[0] += BlockSize */ - MOVQ R9, 0(SI) // - CMPQ R9, $128 // /* if d.t[0] < BlockSize { */ - JGE noincr // - MOVQ 8(SI), R9 // - ADDQ $1, R9 // /* d.t[1]++ */ - MOVQ R9, 8(SI) // -noincr: // /* } */ - - // Load initialization vector - MOVQ iv+48(FP), SI // SI: &iv - BYTE $0xc5; BYTE $0xfe; BYTE $0x6f; BYTE $0x16 // VMOVDQU YMM2, [rsi] - BYTE $0xc5; BYTE $0xfe; BYTE $0x6f; BYTE $0x5e; BYTE $0x20 // VMOVDQU YMM3, 32[rsi] - MOVQ t+72(FP), SI // SI: &t - BYTE $0xc4; BYTE $0x63; BYTE $0x3d; BYTE $0x38; BYTE $0x06 // VINSERTI128 YMM8, YMM8, [rsi], 0 /* Y8 = t[0]+t[1] */ - BYTE $0x00 - MOVQ t+96(FP), SI // SI: &f - BYTE $0xc4; BYTE $0x63; BYTE $0x3d; BYTE $0x38; BYTE $0x06 // VINSERTI128 YMM8, YMM8, [rsi], 1 /* Y8 = t[0]+t[1]+f[0]+f[1] */ - BYTE $0x01 - BYTE $0xc4; BYTE $0xc1; BYTE $0x65; BYTE $0xef; BYTE $0xd8 // VPXOR YMM3,YMM3,YMM8 /* Y3 = Y3 ^ Y8 */ - - BYTE $0xc5; BYTE $0x7e; BYTE $0x6f; BYTE $0x12 // VMOVDQU YMM10, [rdx] /* Y10 = m[0]+ m[1]+ m[2]+ m[3] */ - BYTE $0xc5; BYTE $0x7e; BYTE $0x6f; BYTE $0x5a; BYTE $0x20 // VMOVDQU YMM11, 32[rdx] /* Y11 = m[4]+ m[5]+ m[6]+ m[7] */ - BYTE $0xc5; BYTE $0x7e; BYTE $0x6f; BYTE $0x62; BYTE $0x40 // VMOVDQU YMM12, 64[rdx] /* Y12 = m[8]+ m[9]+m[10]+m[11] */ - BYTE $0xc5; BYTE $0x7e; BYTE $0x6f; BYTE $0x6a; BYTE $0x60 // VMOVDQU YMM13, 96[rdx] /* Y13 = m[12]+m[13]+m[14]+m[15] */ - - LOAD_SHUFFLE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0xc1; BYTE $0x2d; BYTE $0x6c; BYTE $0xe3 // VPUNPCKLQDQ YMM4, YMM10, YMM11 /* m[0], m[4], m[2], m[6] */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x2d; BYTE $0x6d; BYTE $0xeb // VPUNPCKHQDQ YMM5, YMM10, YMM11 /* m[1], m[5], m[3], m[7] */ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xe4 // VPERMQ YMM4, YMM4, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xed // VPERMQ YMM5, YMM5, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0xc1; BYTE $0x1d; BYTE $0x6c; BYTE $0xe5 // VPUNPCKLQDQ YMM4, YMM12, YMM13 /* m[8], m[12], m[10], m[14] */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x1d; BYTE $0x6d; BYTE $0xed // VPUNPCKHQDQ YMM5, YMM12, YMM13 /* m[9], m[13], m[11], m[15] */ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xe4 // VPERMQ YMM4, YMM4, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xed // VPERMQ YMM5, YMM5, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 2 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc5 // VPUNPCKLQDQ YMM8, YMM11, YMM13 /* m[4], ____, ____, m[14] */ - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x03 /* m[14], m[4], ____, ____ */ /* xxxx 0011 = 0x03 */ - BYTE $0x03 - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xcd // VPUNPCKHQDQ YMM9, YMM12, YMM13 /* m[9], m[13], ____, ____ */ - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 /* m[9], m[13], ____, ____ */ /* 0010 0000 = 0x20 */ - BYTE $0x20 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc4 // VPERMQ YMM8, YMM12, 0x02 /* m[10], m[8], ____, ____ */ /* xxxx 0010 = 0x02 */ - BYTE $0x02 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0x30 /* ____, ____, m[15], ____ */ /* xx11 xxxx = 0x30 */ - BYTE $0x30 - BYTE $0xc4; BYTE $0x41; BYTE $0x35; BYTE $0x6c; BYTE $0xcb // VPUNPCKLQDQ YMM9, YMM9, YMM11 /* ____, ____, m[15], m[6] */ - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 /* m[9], m[13], m[15], m[6] */ /* 0011 0000 = 0x30 */ - BYTE $0x30 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc2 // VPERMQ YMM8, YMM10, 0x01 /* m[1], m[0], ____, ____ */ /* xxxx 0001 = 0x01 */ - BYTE $0x01 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xcc // VPUNPCKHQDQ YMM9, YMM11, YMM12 /* m[5], ____, ____, m[11] */ - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x03 /* m[11], m[5], ____, ____ */ /* xxxx 0011 = 0x03 */ - BYTE $0x03 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 /* m[1], m[0], m[11], m[5] */ /* 0010 0000 = 0x20 */ - BYTE $0x20 - - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc5 // VPUNPCKLQDQ YMM8, YMM10, YMM13 /* ___, m[12], m[2], ____ */ - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x09 /* m[12], m[2], ____, ____ */ /* xxxx 1001 = 0x09 */ - BYTE $0x09 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xca // VPUNPCKHQDQ YMM9, YMM11, YMM10 /* ____, ____, m[7], m[3] */ - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 /* m[9], m[13], m[15], m[6] */ /* 0011 0000 = 0x30 */ - BYTE $0x30 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 3 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc5 // VPERMQ YMM8, YMM13, 0x00 - BYTE $0x00 - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xc0 // VPUNPCKHQDQ YMM8, YMM12, YMM8 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xcd // VPUNPCKHQDQ YMM9, YMM11, YMM13 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x21 - BYTE $0x21 - - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6c; BYTE $0xc2 // VPUNPCKLQDQ YMM8, YMM12, YMM10 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0x55 - BYTE $0x55 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM10, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 - BYTE $0x30 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc2 // VPERMQ YMM8, YMM10, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6c; BYTE $0xc0 // VPUNPCKLQDQ YMM8, YMM12, YMM8 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xcc // VPUNPCKHQDQ YMM9, YMM11, YMM12 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x31 - BYTE $0x31 - - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xc3 // VPUNPCKLQDQ YMM8, YMM13, YMM11 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcb // VPERMQ YMM9, YMM11, 0x00 - BYTE $0x00 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6d; BYTE $0xc9 // VPUNPCKHQDQ YMM9, YMM10, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x21 - BYTE $0x21 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 4 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xc2 // VPUNPCKHQDQ YMM8, YMM11, YMM10 - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xcc // VPUNPCKHQDQ YMM9, YMM13, YMM12 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x21 - BYTE $0x21 - - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xc2 // VPUNPCKHQDQ YMM8, YMM12, YMM10 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0x08 - BYTE $0x08 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x20 - BYTE $0x20 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc3 // VPERMQ YMM8, YMM11, 0x55 - BYTE $0x55 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc0 // VPUNPCKLQDQ YMM8, YMM10, YMM8 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM11, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x21 - BYTE $0x21 - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc4 // VPUNPCKLQDQ YMM8, YMM11, YMM12 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xcc // VPUNPCKLQDQ YMM9, YMM10, YMM12 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x21 - BYTE $0x21 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 5 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xc3 // VPUNPCKHQDQ YMM8, YMM12, YMM11 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xcc // VPUNPCKLQDQ YMM9, YMM10, YMM12 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x30 - BYTE $0x30 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc3 // VPERMQ YMM8, YMM11, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc0 // VPUNPCKLQDQ YMM8, YMM10, YMM8 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM11, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x20 - BYTE $0x20 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc4 // VPERMQ YMM8, YMM12, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xc0 // VPUNPCKLQDQ YMM8, YMM13, YMM8 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xca // VPERMQ YMM9, YMM10, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM11, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x31 - BYTE $0x31 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc5 // VPERMQ YMM8, YMM13, 0x00 - BYTE $0x00 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6d; BYTE $0xc0 // VPUNPCKHQDQ YMM8, YMM10, YMM8 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0x55 - BYTE $0x55 - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM12, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x20 - BYTE $0x20 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 6 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc3 // VPUNPCKLQDQ YMM8, YMM10, YMM11 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xcc // VPUNPCKLQDQ YMM9, YMM10, YMM12 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x21 - BYTE $0x21 - - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xc4 // VPUNPCKLQDQ YMM8, YMM13, YMM12 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xca // VPUNPCKHQDQ YMM9, YMM12, YMM10 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 - BYTE $0x30 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc3 // VPERMQ YMM8, YMM11, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xca // VPUNPCKHQDQ YMM9, YMM13, YMM10 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x30 - BYTE $0x30 - - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xc3 // VPUNPCKHQDQ YMM8, YMM13, YMM11 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcc // VPERMQ YMM9, YMM12, 0x55 - BYTE $0x55 - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM13, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 - BYTE $0x30 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 7 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc2 // VPERMQ YMM8, YMM10, 0x55 - BYTE $0x55 - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xc0 // VPUNPCKLQDQ YMM8, YMM13, YMM8 - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xcb // VPUNPCKLQDQ YMM9, YMM13, YMM11 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x30 - BYTE $0x30 - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xc5 // VPUNPCKHQDQ YMM8, YMM11, YMM13 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcc // VPERMQ YMM9, YMM12, 0xaa - BYTE $0xaa - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xc9 // VPUNPCKHQDQ YMM9, YMM13, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x20 - BYTE $0x20 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc3 // VPUNPCKLQDQ YMM8, YMM10, YMM11 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcc // VPERMQ YMM9, YMM12, 0x01 - BYTE $0x01 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 - BYTE $0x20 - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xc2 // VPUNPCKHQDQ YMM8, YMM11, YMM10 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcc // VPERMQ YMM9, YMM12, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM10, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x31 - BYTE $0x31 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 8 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xc3 // VPUNPCKHQDQ YMM8, YMM13, YMM11 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xca // VPERMQ YMM9, YMM10, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xc9 // VPUNPCKLQDQ YMM9, YMM13, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 - BYTE $0x20 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc5 // VPERMQ YMM8, YMM13, 0xaa - BYTE $0xaa - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xc0 // VPUNPCKHQDQ YMM8, YMM12, YMM8 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6d; BYTE $0xcc // VPUNPCKHQDQ YMM9, YMM10, YMM12 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x21 - BYTE $0x21 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xc5 // VPUNPCKHQDQ YMM8, YMM11, YMM13 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6c; BYTE $0xca // VPUNPCKLQDQ YMM9, YMM12, YMM10 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x0c - BYTE $0x0c - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 - BYTE $0x20 - - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc3 // VPUNPCKLQDQ YMM8, YMM10, YMM11 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xcc // VPUNPCKLQDQ YMM9, YMM11, YMM12 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 - BYTE $0x30 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 9 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc5 // VPUNPCKLQDQ YMM8, YMM11, YMM13 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xca // VPERMQ YMM9, YMM10, 0x00 - BYTE $0x00 - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xc9 // VPUNPCKHQDQ YMM9, YMM12, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x31 - BYTE $0x31 - - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xc4 // VPUNPCKHQDQ YMM8, YMM13, YMM12 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcc // VPERMQ YMM9, YMM12, 0x00 - BYTE $0x00 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6d; BYTE $0xc9 // VPUNPCKHQDQ YMM9, YMM10, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x31 - BYTE $0x31 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcc // VPERMQ YMM9, YMM12, 0xaa - BYTE $0xaa - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6d; BYTE $0xc9 // VPUNPCKHQDQ YMM9, YMM10, YMM9 - BYTE $0xc4; BYTE $0xc3; BYTE $0x15; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM13, YMM9, 0x20 - BYTE $0x20 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc3 // VPERMQ YMM8, YMM11, 0xff - BYTE $0xff - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc0 // VPUNPCKLQDQ YMM8, YMM10, YMM8 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcb // VPERMQ YMM9, YMM11, 0x04 - BYTE $0x04 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x21 - BYTE $0x21 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 10 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc4 // VPERMQ YMM8, YMM12, 0x20 - BYTE $0x20 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xca // VPUNPCKHQDQ YMM9, YMM11, YMM10 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x31 - BYTE $0x31 - - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc3 // VPUNPCKLQDQ YMM8, YMM10, YMM11 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcb // VPERMQ YMM9, YMM11, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x31 - BYTE $0x31 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6d; BYTE $0xc4 // VPUNPCKHQDQ YMM8, YMM13, YMM12 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6d; BYTE $0xcd // VPUNPCKHQDQ YMM9, YMM10, YMM13 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x60 - BYTE $0x60 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x31 - BYTE $0x31 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc5 // VPERMQ YMM8, YMM13, 0xaa - BYTE $0xaa - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xc0 // VPUNPCKHQDQ YMM8, YMM12, YMM8 - BYTE $0xc4; BYTE $0x41; BYTE $0x15; BYTE $0x6c; BYTE $0xca // VPUNPCKLQDQ YMM9, YMM13, YMM10 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x21 - BYTE $0x21 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 1 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0xc1; BYTE $0x2d; BYTE $0x6c; BYTE $0xe3 // VPUNPCKLQDQ YMM4, YMM10, YMM11 /* m[0], m[4], m[2], m[6] */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x2d; BYTE $0x6d; BYTE $0xeb // VPUNPCKHQDQ YMM5, YMM10, YMM11 /* m[1], m[5], m[3], m[7] */ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xe4 // VPERMQ YMM4, YMM4, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xed // VPERMQ YMM5, YMM5, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0xc1; BYTE $0x1d; BYTE $0x6c; BYTE $0xe5 // VPUNPCKLQDQ YMM4, YMM12, YMM13 /* m[8], m[12], m[10], m[14] */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x1d; BYTE $0x6d; BYTE $0xed // VPUNPCKHQDQ YMM5, YMM12, YMM13 /* m[9], m[13], m[11], m[15] */ - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xe4 // VPERMQ YMM4, YMM4, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xed // VPERMQ YMM5, YMM5, 0xd8 /* 0x1101 1000 = 0xd8 */ - BYTE $0xd8 - - G1 - G2 - - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 2 - /////////////////////////////////////////////////////////////////////////// - - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6c; BYTE $0xc5 // VPUNPCKLQDQ YMM8, YMM11, YMM13 /* m[4], ____, ____, m[14] */ - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x03 /* m[14], m[4], ____, ____ */ /* xxxx 0011 = 0x03 */ - BYTE $0x03 - BYTE $0xc4; BYTE $0x41; BYTE $0x1d; BYTE $0x6d; BYTE $0xcd // VPUNPCKHQDQ YMM9, YMM12, YMM13 /* m[9], m[13], ____, ____ */ - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 /* m[9], m[13], ____, ____ */ /* 0010 0000 = 0x20 */ - BYTE $0x20 - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc4 // VPERMQ YMM8, YMM12, 0x02 /* m[10], m[8], ____, ____ */ /* xxxx 0010 = 0x02 */ - BYTE $0x02 - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xcd // VPERMQ YMM9, YMM13, 0x30 /* ____, ____, m[15], ____ */ /* xx11 xxxx = 0x30 */ - BYTE $0x30 - BYTE $0xc4; BYTE $0x41; BYTE $0x35; BYTE $0x6c; BYTE $0xcb // VPUNPCKLQDQ YMM9, YMM9, YMM11 /* ____, ____, m[15], m[6] */ - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 /* m[9], m[13], m[15], m[6] */ /* 0011 0000 = 0x30 */ - BYTE $0x30 - - G1 - G2 - - DIAGONALIZE - - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc2 // VPERMQ YMM8, YMM10, 0x01 /* m[1], m[0], ____, ____ */ /* xxxx 0001 = 0x01 */ - BYTE $0x01 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xcc // VPUNPCKHQDQ YMM9, YMM11, YMM12 /* m[5], ____, ____, m[11] */ - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc9 // VPERMQ YMM9, YMM9, 0x03 /* m[11], m[5], ____, ____ */ /* xxxx 0011 = 0x03 */ - BYTE $0x03 - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe1 // VPERM2I128 YMM4, YMM8, YMM9, 0x20 /* m[1], m[0], m[11], m[5] */ /* 0010 0000 = 0x20 */ - BYTE $0x20 - - BYTE $0xc4; BYTE $0x41; BYTE $0x2d; BYTE $0x6c; BYTE $0xc5 // VPUNPCKLQDQ YMM8, YMM10, YMM13 /* ___, m[12], m[2], ____ */ - BYTE $0xc4; BYTE $0x43; BYTE $0xfd; BYTE $0x00; BYTE $0xc0 // VPERMQ YMM8, YMM8, 0x09 /* m[12], m[2], ____, ____ */ /* xxxx 1001 = 0x09 */ - BYTE $0x09 - BYTE $0xc4; BYTE $0x41; BYTE $0x25; BYTE $0x6d; BYTE $0xca // VPUNPCKHQDQ YMM9, YMM11, YMM10 /* ____, ____, m[7], m[3] */ - BYTE $0xc4; BYTE $0xc3; BYTE $0x3d; BYTE $0x46; BYTE $0xe9 // VPERM2I128 YMM5, YMM8, YMM9, 0x30 /* m[9], m[13], m[15], m[6] */ /* 0011 0000 = 0x30 */ - BYTE $0x30 - - G1 - G2 - - UNDIAGONALIZE - - // Reload digest (most current value store in &out) - MOVQ out+144(FP), SI // SI: &in - BYTE $0xc5; BYTE $0x7e; BYTE $0x6f; BYTE $0x26 // VMOVDQU YMM12, [rsi] - BYTE $0xc5; BYTE $0x7e; BYTE $0x6f; BYTE $0x6e; BYTE $0x20 // VMOVDQU YMM13, 32[rsi] - - BYTE $0xc5; BYTE $0xfd; BYTE $0xef; BYTE $0xc2 // VPXOR YMM0,YMM0,YMM2 /* X0 = X0 ^ X4, X1 = X1 ^ X5 */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x7d; BYTE $0xef; BYTE $0xc4 // VPXOR YMM0,YMM0,YMM12 /* X0 = X0 ^ X12, X1 = X1 ^ X13 */ - BYTE $0xc5; BYTE $0xf5; BYTE $0xef; BYTE $0xcb // VPXOR YMM1,YMM1,YMM3 /* X2 = X2 ^ X6, X3 = X3 ^ X7 */ - BYTE $0xc4; BYTE $0xc1; BYTE $0x75; BYTE $0xef; BYTE $0xcd // VPXOR YMM1,YMM1,YMM13 /* X2 = X2 ^ X14, X3 = X3 ^ X15 */ - - // Store digest into &out - MOVQ out+144(FP), SI // SI: &out - BYTE $0xc5; BYTE $0xfe; BYTE $0x7f; BYTE $0x06 // VMOVDQU [rsi], YMM0 - BYTE $0xc5; BYTE $0xfe; BYTE $0x7f; BYTE $0x4e; BYTE $0x20 // VMOVDQU 32[rsi], YMM1 - - // Increment message pointer and check if there's more to do - ADDQ $128, DX // message += 128 - SUBQ $1, R8 - JNZ loop - -complete: - BYTE $0xc5; BYTE $0xf8; BYTE $0x77 // VZEROUPPER /* Prevent further context switches */ - RET - diff --git a/vendor/github.com/minio/blake2b-simd/compressAvx_amd64.go b/vendor/github.com/minio/blake2b-simd/compressAvx_amd64.go deleted file mode 100644 index cfa12c04f..000000000 --- a/vendor/github.com/minio/blake2b-simd/compressAvx_amd64.go +++ /dev/null @@ -1,41 +0,0 @@ -//+build !noasm -//+build !appengine - -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package blake2b - -//go:noescape -func blockAVXLoop(p []uint8, in, iv, t, f, shffle, out []uint64) - -func compressAVX(d *digest, p []uint8) { - var ( - in [8]uint64 - out [8]uint64 - shffle [2]uint64 - ) - - // vector for PSHUFB instruction - shffle[0] = 0x0201000706050403 - shffle[1] = 0x0a09080f0e0d0c0b - - in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7] = d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] - - blockAVXLoop(p, in[:], iv[:], d.t[:], d.f[:], shffle[:], out[:]) - - d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7] -} diff --git a/vendor/github.com/minio/blake2b-simd/compressAvx_amd64.s b/vendor/github.com/minio/blake2b-simd/compressAvx_amd64.s deleted file mode 100644 index f68e17392..000000000 --- a/vendor/github.com/minio/blake2b-simd/compressAvx_amd64.s +++ /dev/null @@ -1,682 +0,0 @@ -//+build !noasm !appengine - -// -// Minio Cloud Storage, (C) 2016 Minio, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// -// Based on SSE implementation from https://github.com/BLAKE2/BLAKE2/blob/master/sse/blake2b.c -// -// Use github.com/fwessels/asm2plan9s on this file to assemble instructions to their Plan9 equivalent -// -// Assembly code below essentially follows the ROUND macro (see blake2b-round.h) which is defined as: -// #define ROUND(r) \ -// LOAD_MSG_ ##r ##_1(b0, b1); \ -// G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// LOAD_MSG_ ##r ##_2(b0, b1); \ -// G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ -// LOAD_MSG_ ##r ##_3(b0, b1); \ -// G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// LOAD_MSG_ ##r ##_4(b0, b1); \ -// G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); -// -// as well as the go equivalent in https://github.com/dchest/blake2b/blob/master/block.go -// -// As in the macro, G1/G2 in the 1st and 2nd half are identical (so literal copy of assembly) -// -// Rounds are also the same, except for the loading of the message (and rounds 1 & 11 and -// rounds 2 & 12 are identical) -// - -#define G1 \ - \ // G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); - LONG $0xd479c1c4; BYTE $0xc0 \ // VPADDQ XMM0,XMM0,XMM8 /* v0 += m[0], v1 += m[2] */ - LONG $0xd471c1c4; BYTE $0xc9 \ // VPADDQ XMM1,XMM1,XMM9 /* v2 += m[4], v3 += m[6] */ - LONG $0xc2d4f9c5 \ // VPADDQ XMM0,XMM0,XMM2 /* v0 += v4, v1 += v5 */ - LONG $0xcbd4f1c5 \ // VPADDQ XMM1,XMM1,XMM3 /* v2 += v6, v3 += v7 */ - LONG $0xf0efc9c5 \ // VPXOR XMM6,XMM6,XMM0 /* v12 ^= v0, v13 ^= v1 */ - LONG $0xf9efc1c5 \ // VPXOR XMM7,XMM7,XMM1 /* v14 ^= v2, v15 ^= v3 */ - LONG $0xf670f9c5; BYTE $0xb1 \ // VPSHUFD XMM6,XMM6,0xb1 /* v12 = v12<<(64-32) | v12>>32, v13 = v13<<(64-32) | v13>>32 */ - LONG $0xff70f9c5; BYTE $0xb1 \ // VPSHUFD XMM7,XMM7,0xb1 /* v14 = v14<<(64-32) | v14>>32, v15 = v15<<(64-32) | v15>>32 */ - LONG $0xe6d4d9c5 \ // VPADDQ XMM4,XMM4,XMM6 /* v8 += v12, v9 += v13 */ - LONG $0xefd4d1c5 \ // VPADDQ XMM5,XMM5,XMM7 /* v10 += v14, v11 += v15 */ - LONG $0xd4efe9c5 \ // VPXOR XMM2,XMM2,XMM4 /* v4 ^= v8, v5 ^= v9 */ - LONG $0xddefe1c5 \ // VPXOR XMM3,XMM3,XMM5 /* v6 ^= v10, v7 ^= v11 */ - LONG $0x0069c2c4; BYTE $0xd4 \ // VPSHUFB XMM2,XMM2,XMM12 /* v4 = v4<<(64-24) | v4>>24, v5 = v5<<(64-24) | v5>>24 */ - LONG $0x0061c2c4; BYTE $0xdc // VPSHUFB XMM3,XMM3,XMM12 /* v6 = v6<<(64-24) | v6>>24, v7 = v7<<(64-24) | v7>>24 */ - -#define G2 \ - \ // G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); - LONG $0xd479c1c4; BYTE $0xc2 \ // VPADDQ XMM0,XMM0,XMM10 /* v0 += m[1], v1 += m[3] */ - LONG $0xd471c1c4; BYTE $0xcb \ // VPADDQ XMM1,XMM1,XMM11 /* v2 += m[5], v3 += m[7] */ - LONG $0xc2d4f9c5 \ // VPADDQ XMM0,XMM0,XMM2 /* v0 += v4, v1 += v5 */ - LONG $0xcbd4f1c5 \ // VPADDQ XMM1,XMM1,XMM3 /* v2 += v6, v3 += v7 */ - LONG $0xf0efc9c5 \ // VPXOR XMM6,XMM6,XMM0 /* v12 ^= v0, v13 ^= v1 */ - LONG $0xf9efc1c5 \ // VPXOR XMM7,XMM7,XMM1 /* v14 ^= v2, v15 ^= v3 */ - LONG $0xf670fbc5; BYTE $0x39 \ // VPSHUFLW XMM6,XMM6,0x39 /* combined with next ... */ - LONG $0xf670fac5; BYTE $0x39 \ // VPSHUFHW XMM6,XMM6,0x39 /* v12 = v12<<(64-16) | v12>>16, v13 = v13<<(64-16) | v13>>16 */ - LONG $0xff70fbc5; BYTE $0x39 \ // VPSHUFLW XMM7,XMM7,0x39 /* combined with next ... */ - LONG $0xff70fac5; BYTE $0x39 \ // VPSHUFHW XMM7,XMM7,0x39 /* v14 = v14<<(64-16) | v14>>16, v15 = v15<<(64-16) | v15>>16 */ - LONG $0xe6d4d9c5 \ // VPADDQ XMM4,XMM4,XMM6 /* v8 += v12, v9 += v13 */ - LONG $0xefd4d1c5 \ // VPADDQ XMM5,XMM5,XMM7 /* v10 += v14, v11 += v15 */ - LONG $0xd4efe9c5 \ // VPXOR XMM2,XMM2,XMM4 /* v4 ^= v8, v5 ^= v9 */ - LONG $0xddefe1c5 \ // VPXOR XMM3,XMM3,XMM5 /* v6 ^= v10, v7 ^= v11 */ - LONG $0xfad469c5 \ // VPADDQ XMM15,XMM2,XMM2 /* temp reg = reg*2 */ - LONG $0xd273e9c5; BYTE $0x3f \ // VPSRLQ XMM2,XMM2,0x3f /* reg = reg>>63 */ - LONG $0xef69c1c4; BYTE $0xd7 \ // VPXOR XMM2,XMM2,XMM15 /* ORed together: v4 = v4<<(64-63) | v4>>63, v5 = v5<<(64-63) | v5>>63 */ - LONG $0xfbd461c5 \ // VPADDQ XMM15,XMM3,XMM3 /* temp reg = reg*2 */ - LONG $0xd373e1c5; BYTE $0x3f \ // VPSRLQ XMM3,XMM3,0x3f /* reg = reg>>63 */ - LONG $0xef61c1c4; BYTE $0xdf // VPXOR XMM3,XMM3,XMM15 /* ORed together: v6 = v6<<(64-63) | v6>>63, v7 = v7<<(64-63) | v7>>63 */ - -#define DIAGONALIZE \ - \ // DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); - MOVOU X6, X13 \ /* t0 = row4l;\ */ - MOVOU X2, X14 \ /* t1 = row2l;\ */ - MOVOU X4, X6 \ /* row4l = row3l;\ */ - MOVOU X5, X4 \ /* row3l = row3h;\ */ - MOVOU X6, X5 \ /* row3h = row4l;\ */ - LONG $0x6c1141c4; BYTE $0xfd \ // VPUNPCKLQDQ XMM15, XMM13, XMM13 /* _mm_unpacklo_epi64(t0, t0) */ - LONG $0x6d41c1c4; BYTE $0xf7 \ // VPUNPCKHQDQ XMM6, XMM7, XMM15 /* row4l = _mm_unpackhi_epi64(row4h, ); \ */ - LONG $0xff6c41c5 \ // VPUNPCKLQDQ XMM15, XMM7, XMM7 /* _mm_unpacklo_epi64(row4h, row4h) */ - LONG $0x6d11c1c4; BYTE $0xff \ // VPUNPCKHQDQ XMM7, XMM13, XMM15 /* row4h = _mm_unpackhi_epi64(t0, ); \ */ - LONG $0xfb6c61c5 \ // VPUNPCKLQDQ XMM15, XMM3, XMM3 /* _mm_unpacklo_epi64(row2h, row2h) */ - LONG $0x6d69c1c4; BYTE $0xd7 \ // VPUNPCKHQDQ XMM2, XMM2, XMM15 /* row2l = _mm_unpackhi_epi64(row2l, ); \ */ - LONG $0x6c0941c4; BYTE $0xfe \ // VPUNPCKLQDQ XMM15, XMM14, XMM14 /* _mm_unpacklo_epi64(t1, t1) */ - LONG $0x6d61c1c4; BYTE $0xdf // VPUNPCKHQDQ XMM3, XMM3, XMM15 /* row2h = _mm_unpackhi_epi64(row2h, ) */ - -#define UNDIAGONALIZE \ - \ // UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); - MOVOU X4, X13 \ /* t0 = row3l;\ */ - MOVOU X5, X4 \ /* row3l = row3h;\ */ - MOVOU X13, X5 \ /* row3h = t0;\ */ - MOVOU X2, X13 \ /* t0 = row2l;\ */ - MOVOU X6, X14 \ /* t1 = row4l;\ */ - LONG $0xfa6c69c5 \ // VPUNPCKLQDQ XMM15, XMM2, XMM2 /* _mm_unpacklo_epi64(row2l, row2l) */ - LONG $0x6d61c1c4; BYTE $0xd7 \ // VPUNPCKHQDQ XMM2, XMM3, XMM15 /* row2l = _mm_unpackhi_epi64(row2h, ); \ */ - LONG $0xfb6c61c5 \ // VPUNPCKLQDQ XMM15, XMM3, XMM3 /* _mm_unpacklo_epi64(row2h, row2h) */ - LONG $0x6d11c1c4; BYTE $0xdf \ // VPUNPCKHQDQ XMM3, XMM13, XMM15 /* row2h = _mm_unpackhi_epi64(t0, ); \ */ - LONG $0xff6c41c5 \ // VPUNPCKLQDQ XMM15, XMM7, XMM7 /* _mm_unpacklo_epi64(row4h, row4h) */ - LONG $0x6d49c1c4; BYTE $0xf7 \ // VPUNPCKHQDQ XMM6, XMM6, XMM15 /* row4l = _mm_unpackhi_epi64(row4l, ); \ */ - LONG $0x6c0941c4; BYTE $0xfe \ // VPUNPCKLQDQ XMM15, XMM14, XMM14 /* _mm_unpacklo_epi64(t1, t1) */ - LONG $0x6d41c1c4; BYTE $0xff // VPUNPCKHQDQ XMM7, XMM7, XMM15 /* row4h = _mm_unpackhi_epi64(row4h, ) */ - -#define LOAD_SHUFFLE \ - \ // Load shuffle value - MOVQ shffle+120(FP), SI \ // SI: &shuffle - MOVOU 0(SI), X12 // X12 = 03040506 07000102 0b0c0d0e 0f08090a - -// func blockAVXLoop(p []uint8, in, iv, t, f, shffle, out []uint64) -TEXT ·blockAVXLoop(SB), 7, $0 - // REGISTER USE - // R8: loop counter - // DX: message pointer - // SI: temp pointer for loading - // X0 - X7: v0 - v15 - // X8 - X11: m[0] - m[7] - // X12: shuffle value - // X13 - X15: temp registers - - // Load digest - MOVQ in+24(FP), SI // SI: &in - MOVOU 0(SI), X0 // X0 = in[0]+in[1] /* row1l = LOAD( &S->h[0] ); */ - MOVOU 16(SI), X1 // X1 = in[2]+in[3] /* row1h = LOAD( &S->h[2] ); */ - MOVOU 32(SI), X2 // X2 = in[4]+in[5] /* row2l = LOAD( &S->h[4] ); */ - MOVOU 48(SI), X3 // X3 = in[6]+in[7] /* row2h = LOAD( &S->h[6] ); */ - - // Already store digest into &out (so we can reload it later generically) - MOVQ out+144(FP), SI // SI: &out - MOVOU X0, 0(SI) // out[0]+out[1] = X0 - MOVOU X1, 16(SI) // out[2]+out[3] = X1 - MOVOU X2, 32(SI) // out[4]+out[5] = X2 - MOVOU X3, 48(SI) // out[6]+out[7] = X3 - - // Initialize message pointer and loop counter - MOVQ message+0(FP), DX // DX: &p (message) - MOVQ message_len+8(FP), R8 // R8: len(message) - SHRQ $7, R8 // len(message) / 128 - CMPQ R8, $0 - JEQ complete - -loop: - // Increment counter - MOVQ t+72(FP), SI // SI: &t - MOVQ 0(SI), R9 - ADDQ $128, R9 // /* d.t[0] += BlockSize */ - MOVQ R9, 0(SI) - CMPQ R9, $128 // /* if d.t[0] < BlockSize { */ - JGE noincr - MOVQ 8(SI), R9 - ADDQ $1, R9 // /* d.t[1]++ */ - MOVQ R9, 8(SI) -noincr: // /* } */ - - // Load initialization vector - MOVQ iv+48(FP), SI // SI: &iv - MOVOU 0(SI), X4 // X4 = iv[0]+iv[1] /* row3l = LOAD( &blake2b_IV[0] ); */ - MOVOU 16(SI), X5 // X5 = iv[2]+iv[3] /* row3h = LOAD( &blake2b_IV[2] ); */ - MOVOU 32(SI), X6 // X6 = iv[4]+iv[5] /* LOAD( &blake2b_IV[4] ) */ - MOVOU 48(SI), X7 // X7 = iv[6]+iv[7] /* LOAD( &blake2b_IV[6] ) */ - MOVQ t+72(FP), SI // SI: &t - MOVOU 0(SI), X8 // X8 = t[0]+t[1] /* LOAD( &S->t[0] ) */ - PXOR X8, X6 // X6 = X6 ^ X8 /* row4l = _mm_xor_si128( , ); */ - MOVQ t+96(FP), SI // SI: &f - MOVOU 0(SI), X8 // X8 = f[0]+f[1] /* LOAD( &S->f[0] ) */ - PXOR X8, X7 // X7 = X7 ^ X8 /* row4h = _mm_xor_si128( , ); */ - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+m[1] - MOVOU 16(DX), X13 // X13 = m[2]+m[3] - MOVOU 32(DX), X14 // X14 = m[4]+m[5] - MOVOU 48(DX), X15 // X15 = m[6]+m[7] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[0], m[2] */ - LONG $0x6c0941c4; BYTE $0xcf // VPUNPCKLQDQ XMM9, XMM14, XMM15 /* m[4], m[6] */ - LONG $0x6d1941c4; BYTE $0xd5 // VPUNPCKHQDQ XMM10, XMM12, XMM13 /* m[1], m[3] */ - LONG $0x6d0941c4; BYTE $0xdf // VPUNPCKHQDQ XMM11, XMM14, XMM15 /* m[5], m[7] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 64(DX), X12 // X12 = m[8]+ m[9] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[8],m[10] */ - LONG $0x6c0941c4; BYTE $0xcf // VPUNPCKLQDQ XMM9, XMM14, XMM15 /* m[12],m[14] */ - LONG $0x6d1941c4; BYTE $0xd5 // VPUNPCKHQDQ XMM10, XMM12, XMM13 /* m[9],m[11] */ - LONG $0x6d0941c4; BYTE $0xdf // VPUNPCKHQDQ XMM11, XMM14, XMM15 /* m[13],m[15] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 2 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 112(DX), X12 // X12 = m[14]+m[15] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[14], m[4] */ - LONG $0x6d0941c4; BYTE $0xcf // VPUNPCKHQDQ XMM9, XMM14, XMM15 /* m[9], m[13] */ - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 48(DX), X15 // X15 = m[6]+ m[7] - LONG $0x6c1141c4; BYTE $0xd6 // VPUNPCKLQDQ XMM10, XMM13, XMM14 /* m[10], m[8] */ - LONG $0x0f0143c4; WORD $0x08dc // VPALIGNR XMM11, XMM15, XMM12, 0x8 /* m[15], m[6] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - LONG $0x0f1943c4; WORD $0x08c4 // VPALIGNR XMM8, XMM12, XMM12, 0x8 /* m[1], m[0] */ - LONG $0x6d0941c4; BYTE $0xcd // VPUNPCKHQDQ XMM9, XMM14, XMM13 /* m[11], m[5] */ - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - LONG $0x6c0941c4; BYTE $0xd4 // VPUNPCKLQDQ XMM10, XMM14, XMM12 /* m[12], m[2] */ - LONG $0x6d1141c4; BYTE $0xdc // VPUNPCKHQDQ XMM11, XMM13, XMM12 /* m[7], m[3] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 3 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 32(DX), X12 // X12 = m[4]+ m[5] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x0f0943c4; WORD $0x08c5 // VPALIGNR XMM8, XMM14, XMM13, 0x8 /* m[11], m[12] */ - LONG $0x6d1941c4; BYTE $0xcf // VPUNPCKHQDQ XMM9, XMM12, XMM15 /* m[5], m[15] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 64(DX), X15 // X15 = m[8]+ m[9] - LONG $0x6c0141c4; BYTE $0xd4 // VPUNPCKLQDQ XMM10, XMM15, XMM12 /* m[8], m[0] */ - LONG $0x6d0941c4; BYTE $0xde // VPUNPCKHQDQ XMM11, XMM14, XMM14 /* ___, m[13] */ - LONG $0x6c1141c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM13, XMM11 /* m[2], ___ */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - LONG $0x6d1941c4; BYTE $0xc4 // VPUNPCKHQDQ XMM8, XMM12, XMM12 /* ___, m[3] */ - LONG $0x6c0141c4; BYTE $0xc0 // VPUNPCKLQDQ XMM8, XMM15, XMM8 /* m[10], ___ */ - LONG $0x6d1141c4; BYTE $0xce // VPUNPCKHQDQ XMM9, XMM13, XMM14 /* m[7], m[9] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X14 // X14 = m[4]+ m[5] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6c0141c4; BYTE $0xd5 // VPUNPCKLQDQ XMM10, XMM15, XMM13 /* m[14], m[6] */ - LONG $0x0f0943c4; WORD $0x08dc // VPALIGNR XMM11, XMM14, XMM12, 0x8 /* m[1], m[4] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 4 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - LONG $0x6d1141c4; BYTE $0xc4 // VPUNPCKHQDQ XMM8, XMM13, XMM12 /* m[7], m[3] */ - LONG $0x6d0141c4; BYTE $0xce // VPUNPCKHQDQ XMM9, XMM15, XMM14 /* m[13], m[11] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 64(DX), X13 // X13 = m[8]+ m[9] - MOVOU 112(DX), X14 // X14 = m[14]+m[15] - LONG $0x6d1141c4; BYTE $0xd4 // VPUNPCKHQDQ XMM10, XMM13, XMM12 /* m[9], m[1] */ - LONG $0x6c0141c4; BYTE $0xde // VPUNPCKLQDQ XMM11, XMM15, XMM14 /* m[12], m[14] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d1141c4; BYTE $0xc5 // VPUNPCKHQDQ XMM8, XMM13, XMM13 /* ___, m[5] */ - LONG $0x6c1941c4; BYTE $0xc0 // VPUNPCKLQDQ XMM8, XMM12, XMM8 /* m[2], ____ */ - LONG $0x6d0141c4; BYTE $0xcf // VPUNPCKHQDQ XMM9, XMM15, XMM15 /* ___, m[15] */ - LONG $0x6c1141c4; BYTE $0xc9 // VPUNPCKLQDQ XMM9, XMM13, XMM9 /* m[4], ____ */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X15 // X15 = m[8]+ m[9] - LONG $0x6c1141c4; BYTE $0xd6 // VPUNPCKLQDQ XMM10, XMM13, XMM14 /* m[6], m[10] */ - LONG $0x6c1941c4; BYTE $0xdf // VPUNPCKLQDQ XMM11, XMM12, XMM15 /* m[0], m[8] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 5 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - LONG $0x6d0941c4; BYTE $0xc5 // VPUNPCKHQDQ XMM8, XMM14, XMM13 /* m[9], m[5] */ - LONG $0x6c1941c4; BYTE $0xcf // VPUNPCKLQDQ XMM9, XMM12, XMM15 /* m[2], m[10] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0941c4; BYTE $0xd6 // VPUNPCKHQDQ XMM10, XMM14, XMM14 /* ___, m[7] */ - LONG $0x6c1941c4; BYTE $0xd2 // VPUNPCKLQDQ XMM10, XMM12, XMM10 /* m[0], ____ */ - LONG $0x6d0141c4; BYTE $0xdf // VPUNPCKHQDQ XMM11, XMM15, XMM15 /* ___, m[15] */ - LONG $0x6c1141c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM13, XMM11 /* m[4], ____ */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0941c4; BYTE $0xc6 // VPUNPCKHQDQ XMM8, XMM14, XMM14 /* ___, m[11] */ - LONG $0x6c0141c4; BYTE $0xc0 // VPUNPCKLQDQ XMM8, XMM15, XMM8 /* m[14], ____ */ - LONG $0x6d1941c4; BYTE $0xcc // VPUNPCKHQDQ XMM9, XMM12, XMM12 /* ___, m[3] */ - LONG $0x6c1141c4; BYTE $0xc9 // VPUNPCKLQDQ XMM9, XMM13, XMM9 /* m[6], ____ */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 64(DX), X13 // X13 = m[8]+ m[9] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - LONG $0x0f0943c4; WORD $0x08d4 // VPALIGNR XMM10, XMM14, XMM12, 0x8 /* m[1], m[12] */ - LONG $0x6d0941c4; BYTE $0xde // VPUNPCKHQDQ XMM11, XMM14, XMM14 /* ___, m[13] */ - LONG $0x6c1141c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM13, XMM11 /* m[8], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 6 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 64(DX), X15 // X15 = m[8]+ m[9] - LONG $0x6c1141c4; BYTE $0xc6 // VPUNPCKLQDQ XMM8, XMM13, XMM14 /* m[2], m[6] */ - LONG $0x6c1941c4; BYTE $0xcf // VPUNPCKLQDQ XMM9, XMM12, XMM15 /* m[0], m[8] */ - MOVOU 80(DX), X12 // X12 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - LONG $0x6c0941c4; BYTE $0xd4 // VPUNPCKLQDQ XMM10, XMM14, XMM12 /* m[12], m[10] */ - LONG $0x6d1941c4; BYTE $0xdd // VPUNPCKHQDQ XMM11, XMM12, XMM13 /* m[11], m[3] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0941c4; BYTE $0xc6 // VPUNPCKHQDQ XMM8, XMM14, XMM14 /* ___, m[7] */ - LONG $0x6c1141c4; BYTE $0xc0 // VPUNPCKLQDQ XMM8, XMM13, XMM8 /* m[4], ____ */ - LONG $0x6d0141c4; BYTE $0xcc // VPUNPCKHQDQ XMM9, XMM15, XMM12 /* m[15], m[1] */ - MOVOU 64(DX), X12 // X12 = m[8]+ m[9] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - LONG $0x6d0941c4; BYTE $0xd5 // VPUNPCKHQDQ XMM10, XMM14, XMM13 /* m[13], m[5] */ - LONG $0x6d1941c4; BYTE $0xdc // VPUNPCKHQDQ XMM11, XMM12, XMM12 /* ___, m[9] */ - LONG $0x6c0141c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM15, XMM11 /* m[14], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 7 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d1941c4; BYTE $0xc4 // VPUNPCKHQDQ XMM8, XMM12, XMM12 /* ___, m[1] */ - LONG $0x6c0941c4; BYTE $0xc0 // VPUNPCKLQDQ XMM8, XMM14, XMM8 /* m[12], ____ */ - LONG $0x6c0141c4; BYTE $0xcd // VPUNPCKLQDQ XMM9, XMM15, XMM13 /* m[14], m[4] */ - MOVOU 80(DX), X12 // X12 = m[10]+m[11] - LONG $0x6d1141c4; BYTE $0xd7 // VPUNPCKHQDQ XMM10, XMM13, XMM15 /* m[5], m[15] */ - LONG $0x0f1943c4; WORD $0x08de // VPALIGNR XMM11, XMM12, XMM14, 0x8 /* m[13], m[10] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[0], m[6] */ - LONG $0x0f0943c4; WORD $0x08ce // VPALIGNR XMM9, XMM14, XMM14, 0x8 /* m[9], m[8] */ - MOVOU 16(DX), X14 // X14 = m[2]+ m[3] - LONG $0x6d1141c4; BYTE $0xd6 // VPUNPCKHQDQ XMM10, XMM13, XMM14 /* m[7], m[3] */ - LONG $0x6d0141c4; BYTE $0xdf // VPUNPCKHQDQ XMM11, XMM15, XMM15 /* ___, m[11] */ - LONG $0x6c0941c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM14, XMM11 /* m[2], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 8 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0941c4; BYTE $0xc5 // VPUNPCKHQDQ XMM8, XMM14, XMM13 /* m[13], m[7] */ - LONG $0x6d1941c4; BYTE $0xcc // VPUNPCKHQDQ XMM9, XMM12, XMM12 /* ___, m[3] */ - LONG $0x6c0941c4; BYTE $0xc9 // VPUNPCKLQDQ XMM9, XMM14, XMM9 /* m[12], ____ */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 64(DX), X13 // X13 = m[8]+ m[9] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - LONG $0x0f0143c4; WORD $0x08d6 // VPALIGNR XMM10, XMM15, XMM14, 0x8 /* m[11], m[14] */ - LONG $0x6d1941c4; BYTE $0xdd // VPUNPCKHQDQ XMM11, XMM12, XMM13 /* m[1], m[9] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d1141c4; BYTE $0xc7 // VPUNPCKHQDQ XMM8, XMM13, XMM15 /* m[5], m[15] */ - LONG $0x6c0941c4; BYTE $0xcc // VPUNPCKLQDQ XMM9, XMM14, XMM12 /* m[8], m[2] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - LONG $0x6c1941c4; BYTE $0xd5 // VPUNPCKLQDQ XMM10, XMM12, XMM13 /* m[0], m[4] */ - LONG $0x6c0941c4; BYTE $0xdf // VPUNPCKLQDQ XMM11, XMM14, XMM15 /* m[6], m[10] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 9 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6c1141c4; BYTE $0xc7 // VPUNPCKLQDQ XMM8, XMM13, XMM15 /* m[6], m[14] */ - LONG $0x0f1943c4; WORD $0x08ce // VPALIGNR XMM9, XMM12, XMM14, 0x8 /* m[11], m[0] */ - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - LONG $0x6d0141c4; BYTE $0xd6 // VPUNPCKHQDQ XMM10, XMM15, XMM14 /* m[15], m[9] */ - LONG $0x0f0943c4; WORD $0x08dd // VPALIGNR XMM11, XMM14, XMM13, 0x8 /* m[3], m[8] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - LONG $0x6d0141c4; BYTE $0xc7 // VPUNPCKHQDQ XMM8, XMM15, XMM15 /* ___, m[13] */ - LONG $0x6c0141c4; BYTE $0xc0 // VPUNPCKLQDQ XMM8, XMM15, XMM8 /* m[12], ____ */ - LONG $0x0f0943c4; WORD $0x08cc // VPALIGNR XMM9, XMM14, XMM12, 0x8 /* m[1], m[10] */ - MOVOU 32(DX), X12 // X12 = m[4]+ m[5] - MOVOU 48(DX), X15 // X15 = m[6]+ m[7] - LONG $0x6d0141c4; BYTE $0xd7 // VPUNPCKHQDQ XMM10, XMM15, XMM15 /* ___, m[7] */ - LONG $0x6c1141c4; BYTE $0xd2 // VPUNPCKLQDQ XMM10, XMM13, XMM10 /* m[2], ____ */ - LONG $0x6d1941c4; BYTE $0xdc // VPUNPCKHQDQ XMM11, XMM12, XMM12 /* ___, m[5] */ - LONG $0x6c1941c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM12, XMM11 /* m[4], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 0 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - LONG $0x6c0141c4; BYTE $0xc6 // VPUNPCKLQDQ XMM8, XMM15, XMM14 /* m[10], m[8] */ - LONG $0x6d1141c4; BYTE $0xcc // VPUNPCKHQDQ XMM9, XMM13, XMM12 /* m[7], m[1] */ - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X14 // X14 = m[4]+ m[5] - LONG $0x6c1941c4; BYTE $0xd6 // VPUNPCKLQDQ XMM10, XMM12, XMM14 /* m[2], m[4] */ - LONG $0x6d0941c4; BYTE $0xde // VPUNPCKHQDQ XMM11, XMM14, XMM14 /* ___, m[5] */ - LONG $0x6c1141c4; BYTE $0xdb // VPUNPCKLQDQ XMM11, XMM13, XMM11 /* m[6], ____ */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 64(DX), X13 // X13 = m[8]+ m[9] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0141c4; BYTE $0xc5 // VPUNPCKHQDQ XMM8, XMM15, XMM13 /* m[15], m[9] */ - LONG $0x6d1941c4; BYTE $0xce // VPUNPCKHQDQ XMM9, XMM12, XMM14 /* m[3], m[13] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - LONG $0x0f0143c4; WORD $0x08d5 // VPALIGNR XMM10, XMM15, XMM13, 0x8 /* m[11], m[14] */ - LONG $0x6c0941c4; BYTE $0xdc // VPUNPCKLQDQ XMM11, XMM14, XMM12 /* m[12], m[0] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 1 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+m[1] - MOVOU 16(DX), X13 // X13 = m[2]+m[3] - MOVOU 32(DX), X14 // X14 = m[4]+m[5] - MOVOU 48(DX), X15 // X15 = m[6]+m[7] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[0], m[2] */ - LONG $0x6c0941c4; BYTE $0xcf // VPUNPCKLQDQ XMM9, XMM14, XMM15 /* m[4], m[6] */ - LONG $0x6d1941c4; BYTE $0xd5 // VPUNPCKHQDQ XMM10, XMM12, XMM13 /* m[1], m[3] */ - LONG $0x6d0941c4; BYTE $0xdf // VPUNPCKHQDQ XMM11, XMM14, XMM15 /* m[5], m[7] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 64(DX), X12 // X12 = m[8]+ m[9] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[8],m[10] */ - LONG $0x6c0941c4; BYTE $0xcf // VPUNPCKLQDQ XMM9, XMM14, XMM15 /* m[12],m[14] */ - LONG $0x6d1941c4; BYTE $0xd5 // VPUNPCKHQDQ XMM10, XMM12, XMM13 /* m[9],m[11] */ - LONG $0x6d0941c4; BYTE $0xdf // VPUNPCKHQDQ XMM11, XMM14, XMM15 /* m[13],m[15] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 2 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 112(DX), X12 // X12 = m[14]+m[15] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - LONG $0x6c1941c4; BYTE $0xc5 // VPUNPCKLQDQ XMM8, XMM12, XMM13 /* m[14], m[4] */ - LONG $0x6d0941c4; BYTE $0xcf // VPUNPCKHQDQ XMM9, XMM14, XMM15 /* m[9], m[13] */ - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 48(DX), X15 // X15 = m[6]+ m[7] - LONG $0x6c1141c4; BYTE $0xd6 // VPUNPCKLQDQ XMM10, XMM13, XMM14 /* m[10], m[8] */ - LONG $0x0f0143c4; WORD $0x08dc // VPALIGNR XMM11, XMM15, XMM12, 0x8 /* m[15], m[6] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - LONG $0x0f1943c4; WORD $0x08c4 // VPALIGNR XMM8, XMM12, XMM12, 0x8 /* m[1], m[0] */ - LONG $0x6d0941c4; BYTE $0xcd // VPUNPCKHQDQ XMM9, XMM14, XMM13 /* m[11], m[5] */ - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - LONG $0x6c0941c4; BYTE $0xd4 // VPUNPCKLQDQ XMM10, XMM14, XMM12 /* m[12], m[2] */ - LONG $0x6d1141c4; BYTE $0xdc // VPUNPCKHQDQ XMM11, XMM13, XMM12 /* m[7], m[3] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - // Reload digest (most current value store in &out) - MOVQ out+144(FP), SI // SI: &in - MOVOU 0(SI), X12 // X12 = in[0]+in[1] /* row1l = LOAD( &S->h[0] ); */ - MOVOU 16(SI), X13 // X13 = in[2]+in[3] /* row1h = LOAD( &S->h[2] ); */ - MOVOU 32(SI), X14 // X14 = in[4]+in[5] /* row2l = LOAD( &S->h[4] ); */ - MOVOU 48(SI), X15 // X15 = in[6]+in[7] /* row2h = LOAD( &S->h[6] ); */ - - // Final computations and prepare for storing - PXOR X4, X0 // X0 = X0 ^ X4 /* row1l = _mm_xor_si128( row3l, row1l ); */ - PXOR X5, X1 // X1 = X1 ^ X5 /* row1h = _mm_xor_si128( row3h, row1h ); */ - PXOR X12, X0 // X0 = X0 ^ X12 /* STORE( &S->h[0], _mm_xor_si128( LOAD( &S->h[0] ), row1l ) ); */ - PXOR X13, X1 // X1 = X1 ^ X13 /* STORE( &S->h[2], _mm_xor_si128( LOAD( &S->h[2] ), row1h ) ); */ - PXOR X6, X2 // X2 = X2 ^ X6 /* row2l = _mm_xor_si128( row4l, row2l ); */ - PXOR X7, X3 // X3 = X3 ^ X7 /* row2h = _mm_xor_si128( row4h, row2h ); */ - PXOR X14, X2 // X2 = X2 ^ X14 /* STORE( &S->h[4], _mm_xor_si128( LOAD( &S->h[4] ), row2l ) ); */ - PXOR X15, X3 // X3 = X3 ^ X15 /* STORE( &S->h[6], _mm_xor_si128( LOAD( &S->h[6] ), row2h ) ); */ - - // Store digest into &out - MOVQ out+144(FP), SI // SI: &out - MOVOU X0, 0(SI) // out[0]+out[1] = X0 - MOVOU X1, 16(SI) // out[2]+out[3] = X1 - MOVOU X2, 32(SI) // out[4]+out[5] = X2 - MOVOU X3, 48(SI) // out[6]+out[7] = X3 - - // Increment message pointer and check if there's more to do - ADDQ $128, DX // message += 128 - SUBQ $1, R8 - JNZ loop - -complete: - RET diff --git a/vendor/github.com/minio/blake2b-simd/compressSse_amd64.go b/vendor/github.com/minio/blake2b-simd/compressSse_amd64.go deleted file mode 100644 index d539a7ade..000000000 --- a/vendor/github.com/minio/blake2b-simd/compressSse_amd64.go +++ /dev/null @@ -1,41 +0,0 @@ -//+build !noasm -//+build !appengine - -/* - * Minio Cloud Storage, (C) 2016 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package blake2b - -//go:noescape -func blockSSELoop(p []uint8, in, iv, t, f, shffle, out []uint64) - -func compressSSE(d *digest, p []uint8) { - var ( - in [8]uint64 - out [8]uint64 - shffle [2]uint64 - ) - - // vector for PSHUFB instruction - shffle[0] = 0x0201000706050403 - shffle[1] = 0x0a09080f0e0d0c0b - - in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7] = d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] - - blockSSELoop(p, in[:], iv[:], d.t[:], d.f[:], shffle[:], out[:]) - - d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7] -} diff --git a/vendor/github.com/minio/blake2b-simd/compressSse_amd64.s b/vendor/github.com/minio/blake2b-simd/compressSse_amd64.s deleted file mode 100644 index 6f31c949e..000000000 --- a/vendor/github.com/minio/blake2b-simd/compressSse_amd64.s +++ /dev/null @@ -1,770 +0,0 @@ -//+build !noasm !appengine - -// -// Minio Cloud Storage, (C) 2016 Minio, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// -// Based on SSE implementation from https://github.com/BLAKE2/BLAKE2/blob/master/sse/blake2b.c -// -// Use github.com/fwessels/asm2plan9s on this file to assemble instructions to their Plan9 equivalent -// -// Assembly code below essentially follows the ROUND macro (see blake2b-round.h) which is defined as: -// #define ROUND(r) \ -// LOAD_MSG_ ##r ##_1(b0, b1); \ -// G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// LOAD_MSG_ ##r ##_2(b0, b1); \ -// G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); \ -// LOAD_MSG_ ##r ##_3(b0, b1); \ -// G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// LOAD_MSG_ ##r ##_4(b0, b1); \ -// G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); \ -// UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); -// -// as well as the go equivalent in https://github.com/dchest/blake2b/blob/master/block.go -// -// As in the macro, G1/G2 in the 1st and 2nd half are identical (so literal copy of assembly) -// -// Rounds are also the same, except for the loading of the message (and rounds 1 & 11 and -// rounds 2 & 12 are identical) -// - -#define G1 \ - \ // G1(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); - LONG $0xd40f4166; BYTE $0xc0 \ // PADDQ XMM0,XMM8 /* v0 += m[0], v1 += m[2] */ - LONG $0xd40f4166; BYTE $0xc9 \ // PADDQ XMM1,XMM9 /* v2 += m[4], v3 += m[6] */ - LONG $0xc2d40f66 \ // PADDQ XMM0,XMM2 /* v0 += v4, v1 += v5 */ - LONG $0xcbd40f66 \ // PADDQ XMM1,XMM3 /* v2 += v6, v3 += v7 */ - LONG $0xf0ef0f66 \ // PXOR XMM6,XMM0 /* v12 ^= v0, v13 ^= v1 */ - LONG $0xf9ef0f66 \ // PXOR XMM7,XMM1 /* v14 ^= v2, v15 ^= v3 */ - LONG $0xf6700f66; BYTE $0xb1 \ // PSHUFD XMM6,XMM6,0xb1 /* v12 = v12<<(64-32) | v12>>32, v13 = v13<<(64-32) | v13>>32 */ - LONG $0xff700f66; BYTE $0xb1 \ // PSHUFD XMM7,XMM7,0xb1 /* v14 = v14<<(64-32) | v14>>32, v15 = v15<<(64-32) | v15>>32 */ - LONG $0xe6d40f66 \ // PADDQ XMM4,XMM6 /* v8 += v12, v9 += v13 */ - LONG $0xefd40f66 \ // PADDQ XMM5,XMM7 /* v10 += v14, v11 += v15 */ - LONG $0xd4ef0f66 \ // PXOR XMM2,XMM4 /* v4 ^= v8, v5 ^= v9 */ - LONG $0xddef0f66 \ // PXOR XMM3,XMM5 /* v6 ^= v10, v7 ^= v11 */ - LONG $0x380f4166; WORD $0xd400 \ // PSHUFB XMM2,XMM12 /* v4 = v4<<(64-24) | v4>>24, v5 = v5<<(64-24) | v5>>24 */ - LONG $0x380f4166; WORD $0xdc00 // PSHUFB XMM3,XMM12 /* v6 = v6<<(64-24) | v6>>24, v7 = v7<<(64-24) | v7>>24 */ - -#define G2 \ - \ // G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1); - LONG $0xd40f4166; BYTE $0xc2 \ // PADDQ XMM0,XMM10 /* v0 += m[1], v1 += m[3] */ - LONG $0xd40f4166; BYTE $0xcb \ // PADDQ XMM1,XMM11 /* v2 += m[5], v3 += m[7] */ - LONG $0xc2d40f66 \ // PADDQ XMM0,XMM2 /* v0 += v4, v1 += v5 */ - LONG $0xcbd40f66 \ // PADDQ XMM1,XMM3 /* v2 += v6, v3 += v7 */ - LONG $0xf0ef0f66 \ // PXOR XMM6,XMM0 /* v12 ^= v0, v13 ^= v1 */ - LONG $0xf9ef0f66 \ // PXOR XMM7,XMM1 /* v14 ^= v2, v15 ^= v3 */ - LONG $0xf6700ff2; BYTE $0x39 \ // PSHUFLW XMM6,XMM6,0x39 /* combined with next ... */ - LONG $0xf6700ff3; BYTE $0x39 \ // PSHUFHW XMM6,XMM6,0x39 /* v12 = v12<<(64-16) | v12>>16, v13 = v13<<(64-16) | v13>>16 */ - LONG $0xff700ff2; BYTE $0x39 \ // PSHUFLW XMM7,XMM7,0x39 /* combined with next ... */ - LONG $0xff700ff3; BYTE $0x39 \ // PSHUFHW XMM7,XMM7,0x39 /* v14 = v14<<(64-16) | v14>>16, v15 = v15<<(64-16) | v15>>16 */ - LONG $0xe6d40f66 \ // PADDQ XMM4,XMM6 /* v8 += v12, v9 += v13 */ - LONG $0xefd40f66 \ // PADDQ XMM5,XMM7 /* v10 += v14, v11 += v15 */ - LONG $0xd4ef0f66 \ // PXOR XMM2,XMM4 /* v4 ^= v8, v5 ^= v9 */ - LONG $0xddef0f66 \ // PXOR XMM3,XMM5 /* v6 ^= v10, v7 ^= v11 */ - MOVOU X2, X15 \ - LONG $0xd40f4466; BYTE $0xfa \ // PADDQ XMM15,XMM2 /* temp reg = reg*2 */ - LONG $0xd2730f66; BYTE $0x3f \ // PSRLQ XMM2,0x3f /* reg = reg>>63 */ - LONG $0xef0f4166; BYTE $0xd7 \ // PXOR XMM2,XMM15 /* ORed together: v4 = v4<<(64-63) | v4>>63, v5 = v5<<(64-63) | v5>>63 */ - MOVOU X3, X15 \ - LONG $0xd40f4466; BYTE $0xfb \ // PADDQ XMM15,XMM3 /* temp reg = reg*2 */ - LONG $0xd3730f66; BYTE $0x3f \ // PSRLQ XMM3,0x3f /* reg = reg>>63 */ - LONG $0xef0f4166; BYTE $0xdf // PXOR XMM3,XMM15 /* ORed together: v6 = v6<<(64-63) | v6>>63, v7 = v7<<(64-63) | v7>>63 */ - -#define DIAGONALIZE \ - \ // DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); - MOVOU X6, X13 \ /* t0 = row4l;\ */ - MOVOU X2, X14 \ /* t1 = row2l;\ */ - MOVOU X4, X6 \ /* row4l = row3l;\ */ - MOVOU X5, X4 \ /* row3l = row3h;\ */ - MOVOU X6, X5 \ /* row3h = row4l;\ */ - LONG $0x6c0f4566; BYTE $0xfd \ // PUNPCKLQDQ XMM15, XMM13 /* _mm_unpacklo_epi64(t0, t0) */ - MOVOU X7, X6 \ - LONG $0x6d0f4166; BYTE $0xf7 \ // PUNPCKHQDQ XMM6, XMM15 /* row4l = _mm_unpackhi_epi64(row4h, ); \ */ - LONG $0x6c0f4466; BYTE $0xff \ // PUNPCKLQDQ XMM15, XMM7 /* _mm_unpacklo_epi64(row4h, row4h) */ - MOVOU X13, X7 \ - LONG $0x6d0f4166; BYTE $0xff \ // PUNPCKHQDQ XMM7, XMM15 /* row4h = _mm_unpackhi_epi64(t0, ); \ */ - LONG $0x6c0f4466; BYTE $0xfb \ // PUNPCKLQDQ XMM15, XMM3 /* _mm_unpacklo_epi64(row2h, row2h) */ - LONG $0x6d0f4166; BYTE $0xd7 \ // PUNPCKHQDQ XMM2, XMM15 /* row2l = _mm_unpackhi_epi64(row2l, ); \ */ - LONG $0x6c0f4566; BYTE $0xfe \ // PUNPCKLQDQ XMM15, XMM14 /* _mm_unpacklo_epi64(t1, t1) */ - LONG $0x6d0f4166; BYTE $0xdf // PUNPCKHQDQ XMM3, XMM15 /* row2h = _mm_unpackhi_epi64(row2h, ) */ - -#define UNDIAGONALIZE \ - \ // UNDIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h); - MOVOU X4, X13 \ /* t0 = row3l;\ */ - MOVOU X5, X4 \ /* row3l = row3h;\ */ - MOVOU X13, X5 \ /* row3h = t0;\ */ - MOVOU X2, X13 \ /* t0 = row2l;\ */ - MOVOU X6, X14 \ /* t1 = row4l;\ */ - LONG $0x6c0f4466; BYTE $0xfa \ // PUNPCKLQDQ XMM15, XMM2 /* _mm_unpacklo_epi64(row2l, row2l) */ - MOVOU X3, X2 \ - LONG $0x6d0f4166; BYTE $0xd7 \ // PUNPCKHQDQ XMM2, XMM15 /* row2l = _mm_unpackhi_epi64(row2h, ); \ */ - LONG $0x6c0f4466; BYTE $0xfb \ // PUNPCKLQDQ XMM15, XMM3 /* _mm_unpacklo_epi64(row2h, row2h) */ - MOVOU X13, X3 \ - LONG $0x6d0f4166; BYTE $0xdf \ // PUNPCKHQDQ XMM3, XMM15 /* row2h = _mm_unpackhi_epi64(t0, ); \ */ - LONG $0x6c0f4466; BYTE $0xff \ // PUNPCKLQDQ XMM15, XMM7 /* _mm_unpacklo_epi64(row4h, row4h) */ - LONG $0x6d0f4166; BYTE $0xf7 \ // PUNPCKHQDQ XMM6, XMM15 /* row4l = _mm_unpackhi_epi64(row4l, ); \ */ - LONG $0x6c0f4566; BYTE $0xfe \ // PUNPCKLQDQ XMM15, XMM14 /* _mm_unpacklo_epi64(t1, t1) */ - LONG $0x6d0f4166; BYTE $0xff // PUNPCKHQDQ XMM7, XMM15 /* row4h = _mm_unpackhi_epi64(row4h, ) */ - -#define LOAD_SHUFFLE \ - \ // Load shuffle value - MOVQ shffle+120(FP), SI \ // SI: &shuffle - MOVOU 0(SI), X12 // X12 = 03040506 07000102 0b0c0d0e 0f08090a - -// func blockSSELoop(p []uint8, in, iv, t, f, shffle, out []uint64) -TEXT ·blockSSELoop(SB), 7, $0 - // REGISTER USE - // R8: loop counter - // DX: message pointer - // SI: temp pointer for loading - // X0 - X7: v0 - v15 - // X8 - X11: m[0] - m[7] - // X12: shuffle value - // X13 - X15: temp registers - - // Load digest - MOVQ in+24(FP), SI // SI: &in - MOVOU 0(SI), X0 // X0 = in[0]+in[1] /* row1l = LOAD( &S->h[0] ); */ - MOVOU 16(SI), X1 // X1 = in[2]+in[3] /* row1h = LOAD( &S->h[2] ); */ - MOVOU 32(SI), X2 // X2 = in[4]+in[5] /* row2l = LOAD( &S->h[4] ); */ - MOVOU 48(SI), X3 // X3 = in[6]+in[7] /* row2h = LOAD( &S->h[6] ); */ - - // Already store digest into &out (so we can reload it later generically) - MOVQ out+144(FP), SI // SI: &out - MOVOU X0, 0(SI) // out[0]+out[1] = X0 - MOVOU X1, 16(SI) // out[2]+out[3] = X1 - MOVOU X2, 32(SI) // out[4]+out[5] = X2 - MOVOU X3, 48(SI) // out[6]+out[7] = X3 - - // Initialize message pointer and loop counter - MOVQ message+0(FP), DX // DX: &p (message) - MOVQ message_len+8(FP), R8 // R8: len(message) - SHRQ $7, R8 // len(message) / 128 - CMPQ R8, $0 - JEQ complete - -loop: - // Increment counter - MOVQ t+72(FP), SI // SI: &t - MOVQ 0(SI), R9 - ADDQ $128, R9 // /* d.t[0] += BlockSize */ - MOVQ R9, 0(SI) - CMPQ R9, $128 // /* if d.t[0] < BlockSize { */ - JGE noincr - MOVQ 8(SI), R9 - ADDQ $1, R9 // /* d.t[1]++ */ - MOVQ R9, 8(SI) - -noincr: // /* } */ - - // Load initialization vector - MOVQ iv+48(FP), SI // SI: &iv - MOVOU 0(SI), X4 // X4 = iv[0]+iv[1] /* row3l = LOAD( &blake2b_IV[0] ); */ - MOVOU 16(SI), X5 // X5 = iv[2]+iv[3] /* row3h = LOAD( &blake2b_IV[2] ); */ - MOVOU 32(SI), X6 // X6 = iv[4]+iv[5] /* LOAD( &blake2b_IV[4] ) */ - MOVOU 48(SI), X7 // X7 = iv[6]+iv[7] /* LOAD( &blake2b_IV[6] ) */ - MOVQ t+72(FP), SI // SI: &t - MOVOU 0(SI), X8 // X8 = t[0]+t[1] /* LOAD( &S->t[0] ) */ - PXOR X8, X6 // X6 = X6 ^ X8 /* row4l = _mm_xor_si128( , ); */ - MOVQ t+96(FP), SI // SI: &f - MOVOU 0(SI), X8 // X8 = f[0]+f[1] /* LOAD( &S->f[0] ) */ - PXOR X8, X7 // X7 = X7 ^ X8 /* row4h = _mm_xor_si128( , ); */ - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+m[1] - MOVOU 16(DX), X13 // X13 = m[2]+m[3] - MOVOU 32(DX), X14 // X14 = m[4]+m[5] - MOVOU 48(DX), X15 // X15 = m[6]+m[7] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[0], m[2] */ - MOVOU X14, X9 - LONG $0x6c0f4566; BYTE $0xcf // PUNPCKLQDQ XMM9, XMM15 /* m[4], m[6] */ - MOVOU X12, X10 - LONG $0x6d0f4566; BYTE $0xd5 // PUNPCKHQDQ XMM10, XMM13 /* m[1], m[3] */ - MOVOU X14, X11 - LONG $0x6d0f4566; BYTE $0xdf // PUNPCKHQDQ XMM11, XMM15 /* m[5], m[7] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 64(DX), X12 // X12 = m[8]+ m[9] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[8],m[10] */ - MOVOU X14, X9 - LONG $0x6c0f4566; BYTE $0xcf // PUNPCKLQDQ XMM9, XMM15 /* m[12],m[14] */ - MOVOU X12, X10 - LONG $0x6d0f4566; BYTE $0xd5 // PUNPCKHQDQ XMM10, XMM13 /* m[9],m[11] */ - MOVOU X14, X11 - LONG $0x6d0f4566; BYTE $0xdf // PUNPCKHQDQ XMM11, XMM15 /* m[13],m[15] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 2 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 112(DX), X12 // X12 = m[14]+m[15] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[14], m[4] */ - MOVOU X14, X9 - LONG $0x6d0f4566; BYTE $0xcf // PUNPCKHQDQ XMM9, XMM15 /* m[9], m[13] */ - MOVOU 80(DX), X10 // X10 = m[10]+m[11] - MOVOU 48(DX), X11 // X11 = m[6]+ m[7] - LONG $0x6c0f4566; BYTE $0xd6 // PUNPCKLQDQ XMM10, XMM14 /* m[10], m[8] */ - LONG $0x3a0f4566; WORD $0xdc0f; BYTE $0x08 // PALIGNR XMM11, XMM12, 0x8 /* m[15], m[6] */; ; ; ; ; - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU X12, X8 - LONG $0x3a0f4566; WORD $0xc40f; BYTE $0x08 // PALIGNR XMM8, XMM12, 0x8 /* m[1], m[0] */ - MOVOU X14, X9 - LONG $0x6d0f4566; BYTE $0xcd // PUNPCKHQDQ XMM9, XMM13 /* m[11], m[5] */ - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X11 // X11 = m[6]+ m[7] - MOVOU 96(DX), X10 // X10 = m[12]+m[13] - LONG $0x6c0f4566; BYTE $0xd4 // PUNPCKLQDQ XMM10, XMM12 /* m[12], m[2] */ - LONG $0x6d0f4566; BYTE $0xdc // PUNPCKHQDQ XMM11, XMM12 /* m[7], m[3] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 3 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 32(DX), X12 // X12 = m[4]+ m[5] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X14, X8 - LONG $0x3a0f4566; WORD $0xc50f; BYTE $0x08 // PALIGNR XMM8, XMM13, 0x8 /* m[11], m[12] */ - MOVOU X12, X9 - LONG $0x6d0f4566; BYTE $0xcf // PUNPCKHQDQ XMM9, XMM15 /* m[5], m[15] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 64(DX), X10 // X10 = m[8]+ m[9] - LONG $0x6c0f4566; BYTE $0xd4 // PUNPCKLQDQ XMM10, XMM12 /* m[8], m[0] */ - LONG $0x6d0f4566; BYTE $0xf6 // PUNPCKHQDQ XMM14, XMM14 /* ___, m[13] */ - MOVOU X13, X11 - LONG $0x6c0f4566; BYTE $0xde // PUNPCKLQDQ XMM11, XMM14 /* m[2], ___ */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - MOVOU X12, X9 - LONG $0x6d0f4566; BYTE $0xcc // PUNPCKHQDQ XMM9, XMM12 /* ___, m[3] */ - MOVOU X15, X8 - LONG $0x6c0f4566; BYTE $0xc1 // PUNPCKLQDQ XMM8, XMM9 /* m[10], ___ */ - MOVOU X13, X9 - LONG $0x6d0f4566; BYTE $0xce // PUNPCKHQDQ XMM9, XMM14 /* m[7], m[9] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X11 // X11 = m[4]+ m[5] - MOVOU 112(DX), X10 // X10 = m[14]+m[15] - LONG $0x6c0f4566; BYTE $0xd5 // PUNPCKLQDQ XMM10, XMM13 /* m[14], m[6] */ - LONG $0x3a0f4566; WORD $0xdc0f; BYTE $0x08 // PALIGNR XMM11, XMM12, 0x8 /* m[1], m[4] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 4 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - MOVOU X13, X8 - LONG $0x6d0f4566; BYTE $0xc4 // PUNPCKHQDQ XMM8, XMM12 /* m[7], m[3] */ - MOVOU X15, X9 - LONG $0x6d0f4566; BYTE $0xce // PUNPCKHQDQ XMM9, XMM14 /* m[13], m[11] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 64(DX), X10 // X10 = m[8]+ m[9] - MOVOU 112(DX), X14 // X14 = m[14]+m[15] - LONG $0x6d0f4566; BYTE $0xd4 // PUNPCKHQDQ XMM10, XMM12 /* m[9], m[1] */ - MOVOU X15, X11 - LONG $0x6c0f4566; BYTE $0xde // PUNPCKLQDQ XMM11, XMM14 /* m[12], m[14] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X13, X9 - LONG $0x6d0f4566; BYTE $0xcd // PUNPCKHQDQ XMM9, XMM13 /* ___, m[5] */ - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc1 // PUNPCKLQDQ XMM8, XMM9 /* m[2], ____ */ - MOVOU X15, X10 - LONG $0x6d0f4566; BYTE $0xd7 // PUNPCKHQDQ XMM10, XMM15 /* ___, m[15] */ - MOVOU X13, X9 - LONG $0x6c0f4566; BYTE $0xca // PUNPCKLQDQ XMM9, XMM10 /* m[4], ____ */ - MOVOU 0(DX), X11 // X11 = m[0]+ m[1] - MOVOU 48(DX), X10 // X10 = m[6]+ m[7] - MOVOU 64(DX), X15 // X15 = m[8]+ m[9] - LONG $0x6c0f4566; BYTE $0xd6 // PUNPCKLQDQ XMM10, XMM14 /* m[6], m[10] */ - LONG $0x6c0f4566; BYTE $0xdf // PUNPCKLQDQ XMM11, XMM15 /* m[0], m[8] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 5 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - MOVOU X14, X8 - LONG $0x6d0f4566; BYTE $0xc5 // PUNPCKHQDQ XMM8, XMM13 /* m[9], m[5] */ - MOVOU X12, X9 - LONG $0x6c0f4566; BYTE $0xcf // PUNPCKLQDQ XMM9, XMM15 /* m[2], m[10] */ - MOVOU 0(DX), X10 // X10 = m[0]+ m[1] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0f4566; BYTE $0xf6 // PUNPCKHQDQ XMM14, XMM14 /* ___, m[7] */ - LONG $0x6c0f4566; BYTE $0xd6 // PUNPCKLQDQ XMM10, XMM14 /* m[0], ____ */ - LONG $0x6d0f4566; BYTE $0xff // PUNPCKHQDQ XMM15, XMM15 /* ___, m[15] */ - MOVOU X13, X11 - LONG $0x6c0f4566; BYTE $0xdf // PUNPCKLQDQ XMM11, XMM15 /* m[4], ____ */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - LONG $0x6d0f4566; BYTE $0xf6 // PUNPCKHQDQ XMM14, XMM14 /* ___, m[11] */ - MOVOU X15, X8 - LONG $0x6c0f4566; BYTE $0xc6 // PUNPCKLQDQ XMM8, XMM14 /* m[14], ____ */ - LONG $0x6d0f4566; BYTE $0xe4 // PUNPCKHQDQ XMM12, XMM12 /* ___, m[3] */ - MOVOU X13, X9 - LONG $0x6c0f4566; BYTE $0xcc // PUNPCKLQDQ XMM9, XMM12 /* m[6], ____ */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 64(DX), X11 // X11 = m[8]+ m[9] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU X14, X10 - LONG $0x3a0f4566; WORD $0xd40f; BYTE $0x08 // PALIGNR XMM10, XMM12, 0x8 /* m[1], m[12] */ - LONG $0x6d0f4566; BYTE $0xf6 // PUNPCKHQDQ XMM14, XMM14 /* ___, m[13] */ - LONG $0x6c0f4566; BYTE $0xde // PUNPCKLQDQ XMM11, XMM14 /* m[8], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 6 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 64(DX), X15 // X15 = m[8]+ m[9] - MOVOU X13, X8 - LONG $0x6c0f4566; BYTE $0xc6 // PUNPCKLQDQ XMM8, XMM14 /* m[2], m[6] */ - MOVOU X12, X9 - LONG $0x6c0f4566; BYTE $0xcf // PUNPCKLQDQ XMM9, XMM15 /* m[0], m[8] */ - MOVOU 80(DX), X12 // X12 = m[10]+m[11] - MOVOU 96(DX), X10 // X10 = m[12]+m[13] - LONG $0x6c0f4566; BYTE $0xd4 // PUNPCKLQDQ XMM10, XMM12 /* m[12], m[10] */ - MOVOU X12, X11 - LONG $0x6d0f4566; BYTE $0xdd // PUNPCKHQDQ XMM11, XMM13 /* m[11], m[3] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 48(DX), X14 // X14 = m[6]+ m[7] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X14, X9 - LONG $0x6d0f4566; BYTE $0xce // PUNPCKHQDQ XMM9, XMM14 /* ___, m[7] */ - MOVOU X13, X8 - LONG $0x6c0f4566; BYTE $0xc1 // PUNPCKLQDQ XMM8, XMM9 /* m[4], ____ */ - MOVOU X15, X9 - LONG $0x6d0f4566; BYTE $0xcc // PUNPCKHQDQ XMM9, XMM12 /* m[15], m[1] */ - MOVOU 64(DX), X12 // X12 = m[8]+ m[9] - MOVOU 96(DX), X10 // X10 = m[12]+m[13] - LONG $0x6d0f4566; BYTE $0xd5 // PUNPCKHQDQ XMM10, XMM13 /* m[13], m[5] */ - LONG $0x6d0f4566; BYTE $0xe4 // PUNPCKHQDQ XMM12, XMM12 /* ___, m[9] */ - MOVOU X15, X11 - LONG $0x6c0f4566; BYTE $0xdc // PUNPCKLQDQ XMM11, XMM12 /* m[14], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 7 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X12, X9 - LONG $0x6d0f4566; BYTE $0xcc // PUNPCKHQDQ XMM9, XMM12 /* ___, m[1] */ - MOVOU X14, X8 - LONG $0x6c0f4566; BYTE $0xc1 // PUNPCKLQDQ XMM8, XMM9 /* m[12], ____ */ - MOVOU X15, X9 - LONG $0x6c0f4566; BYTE $0xcd // PUNPCKLQDQ XMM9, XMM13 /* m[14], m[4] */ - MOVOU 80(DX), X11 // X11 = m[10]+m[11] - MOVOU X13, X10 - LONG $0x6d0f4566; BYTE $0xd7 // PUNPCKHQDQ XMM10, XMM15 /* m[5], m[15] */ - LONG $0x3a0f4566; WORD $0xde0f; BYTE $0x08 // PALIGNR XMM11, XMM14, 0x8 /* m[13], m[10] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[0], m[6] */ - MOVOU X14, X9 - LONG $0x3a0f4566; WORD $0xce0f; BYTE $0x08 // PALIGNR XMM9, XMM14, 0x8 /* m[9], m[8] */ - MOVOU 16(DX), X11 // X14 = m[2]+ m[3] - MOVOU X13, X10 - LONG $0x6d0f4566; BYTE $0xd3 // PUNPCKHQDQ XMM10, XMM11 /* m[7], m[3] */ - LONG $0x6d0f4566; BYTE $0xff // PUNPCKHQDQ XMM15, XMM15 /* ___, m[11] */ - LONG $0x6c0f4566; BYTE $0xdf // PUNPCKLQDQ XMM11, XMM15 /* m[2], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 8 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X14, X8 - LONG $0x6d0f4566; BYTE $0xc5 // PUNPCKHQDQ XMM8, XMM13 /* m[13], m[7] */ - MOVOU X12, X10 - LONG $0x6d0f4566; BYTE $0xd4 // PUNPCKHQDQ XMM10, XMM12 /* ___, m[3] */ - MOVOU X14, X9 - LONG $0x6c0f4566; BYTE $0xca // PUNPCKLQDQ XMM9, XMM10 /* m[12], ____ */ - MOVOU 0(DX), X11 // X11 = m[0]+ m[1] - MOVOU 64(DX), X13 // X13 = m[8]+ m[9] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU X15, X10 - LONG $0x3a0f4566; WORD $0xd60f; BYTE $0x08 // PALIGNR XMM10, XMM14, 0x8 /* m[11], m[14] */ - LONG $0x6d0f4566; BYTE $0xdd // PUNPCKHQDQ XMM11, XMM13 /* m[1], m[9] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X13, X8 - LONG $0x6d0f4566; BYTE $0xc7 // PUNPCKHQDQ XMM8, XMM15 /* m[5], m[15] */ - MOVOU X14, X9 - LONG $0x6c0f4566; BYTE $0xcc // PUNPCKLQDQ XMM9, XMM12 /* m[8], m[2] */ - MOVOU 0(DX), X10 // X10 = m[0]+ m[1] - MOVOU 48(DX), X11 // X11 = m[6]+ m[7] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - LONG $0x6c0f4566; BYTE $0xd5 // PUNPCKLQDQ XMM10, XMM13 /* m[0], m[4] */ - LONG $0x6c0f4566; BYTE $0xdf // PUNPCKLQDQ XMM11, XMM15 /* m[6], m[10] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 9 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X13, X8 - LONG $0x6c0f4566; BYTE $0xc7 // PUNPCKLQDQ XMM8, XMM15 /* m[6], m[14] */ - MOVOU X12, X9 - LONG $0x3a0f4566; WORD $0xce0f; BYTE $0x08 // PALIGNR XMM9, XMM14, 0x8 /* m[11], m[0] */ - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 64(DX), X11 // X11 = m[8]+ m[9] - MOVOU X15, X10 - LONG $0x6d0f4566; BYTE $0xd3 // PUNPCKHQDQ XMM10, XMM11 /* m[15], m[9] */ - LONG $0x3a0f4566; WORD $0xdd0f; BYTE $0x08 // PALIGNR XMM11, XMM13, 0x8 /* m[3], m[8] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 16(DX), X13 // X13 = m[2]+ m[3] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - MOVOU X15, X9 - LONG $0x6d0f4566; BYTE $0xcf // PUNPCKHQDQ XMM9, XMM15 /* ___, m[13] */ - MOVOU X15, X8 - LONG $0x6c0f4566; BYTE $0xc1 // PUNPCKLQDQ XMM8, XMM9 /* m[12], ____ */ - MOVOU X14, X9 - LONG $0x3a0f4566; WORD $0xcc0f; BYTE $0x08 // PALIGNR XMM9, XMM12, 0x8 /* m[1], m[10] */ - MOVOU 32(DX), X12 // X12 = m[4]+ m[5] - MOVOU 48(DX), X15 // X15 = m[6]+ m[7] - MOVOU X15, X11 - LONG $0x6d0f4566; BYTE $0xdf // PUNPCKHQDQ XMM11, XMM15 /* ___, m[7] */ - MOVOU X13, X10 - LONG $0x6c0f4566; BYTE $0xd3 // PUNPCKLQDQ XMM10, XMM11 /* m[2], ____ */ - MOVOU X12, X15 - LONG $0x6d0f4566; BYTE $0xfc // PUNPCKHQDQ XMM15, XMM12 /* ___, m[5] */ - MOVOU X12, X11 - LONG $0x6c0f4566; BYTE $0xdf // PUNPCKLQDQ XMM11, XMM15 /* m[4], ____ */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 0 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 48(DX), X13 // X13 = m[6]+ m[7] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 80(DX), X15 // X15 = m[10]+m[11] - MOVOU X15, X8 - LONG $0x6c0f4566; BYTE $0xc6 // PUNPCKLQDQ XMM8, XMM14 /* m[10], m[8] */ - MOVOU X13, X9 - LONG $0x6d0f4566; BYTE $0xcc // PUNPCKHQDQ XMM9, XMM12 /* m[7], m[1] */ - MOVOU 16(DX), X10 // X10 = m[2]+ m[3] - MOVOU 32(DX), X14 // X14 = m[4]+ m[5] - LONG $0x6c0f4566; BYTE $0xd6 // PUNPCKLQDQ XMM10, XMM14 /* m[2], m[4] */ - MOVOU X14, X15 - LONG $0x6d0f4566; BYTE $0xfe // PUNPCKHQDQ XMM15, XMM14 /* ___, m[5] */ - MOVOU X13, X11 - LONG $0x6c0f4566; BYTE $0xdf // PUNPCKLQDQ XMM11, XMM15 /* m[6], ____ */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 64(DX), X13 // X13 = m[8]+ m[9] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X15, X8 - LONG $0x6d0f4566; BYTE $0xc5 // PUNPCKHQDQ XMM8, XMM13 /* m[15], m[9] */ - MOVOU X12, X9 - LONG $0x6d0f4566; BYTE $0xce // PUNPCKHQDQ XMM9, XMM14 /* m[3], m[13] */ - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU X15, X10 - LONG $0x3a0f4566; WORD $0xd50f; BYTE $0x08 // PALIGNR XMM10, XMM13, 0x8 /* m[11], m[14] */ - MOVOU X14, X11 - LONG $0x6c0f4566; BYTE $0xdc // PUNPCKLQDQ XMM11, XMM12 /* m[12], m[0] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 1 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+m[1] - MOVOU 16(DX), X13 // X13 = m[2]+m[3] - MOVOU 32(DX), X14 // X14 = m[4]+m[5] - MOVOU 48(DX), X15 // X15 = m[6]+m[7] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[0], m[2] */ - MOVOU X14, X9 - LONG $0x6c0f4566; BYTE $0xcf // PUNPCKLQDQ XMM9, XMM15 /* m[4], m[6] */ - MOVOU X12, X10 - LONG $0x6d0f4566; BYTE $0xd5 // PUNPCKHQDQ XMM10, XMM13 /* m[1], m[3] */ - MOVOU X14, X11 - LONG $0x6d0f4566; BYTE $0xdf // PUNPCKHQDQ XMM11, XMM15 /* m[5], m[7] */ - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 64(DX), X12 // X12 = m[8]+ m[9] - MOVOU 80(DX), X13 // X13 = m[10]+m[11] - MOVOU 96(DX), X14 // X14 = m[12]+m[13] - MOVOU 112(DX), X15 // X15 = m[14]+m[15] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[8],m[10] */ - MOVOU X14, X9 - LONG $0x6c0f4566; BYTE $0xcf // PUNPCKLQDQ XMM9, XMM15 /* m[12],m[14] */ - MOVOU X12, X10 - LONG $0x6d0f4566; BYTE $0xd5 // PUNPCKHQDQ XMM10, XMM13 /* m[9],m[11] */ - MOVOU X14, X11 - LONG $0x6d0f4566; BYTE $0xdf // PUNPCKHQDQ XMM11, XMM15 /* m[13],m[15] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - /////////////////////////////////////////////////////////////////////////// - // R O U N D 1 2 - /////////////////////////////////////////////////////////////////////////// - - // LOAD_MSG_ ##r ##_1 / ##_2(b0, b1); (X12 is temp register) - MOVOU 112(DX), X12 // X12 = m[14]+m[15] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 64(DX), X14 // X14 = m[8]+ m[9] - MOVOU 96(DX), X15 // X15 = m[12]+m[13] - MOVOU X12, X8 - LONG $0x6c0f4566; BYTE $0xc5 // PUNPCKLQDQ XMM8, XMM13 /* m[14], m[4] */ - MOVOU X14, X9 - LONG $0x6d0f4566; BYTE $0xcf // PUNPCKHQDQ XMM9, XMM15 /* m[9], m[13] */ - MOVOU 80(DX), X10 // X10 = m[10]+m[11] - MOVOU 48(DX), X11 // X11 = m[6]+ m[7] - LONG $0x6c0f4566; BYTE $0xd6 // PUNPCKLQDQ XMM10, XMM14 /* m[10], m[8] */ - LONG $0x3a0f4566; WORD $0xdc0f; BYTE $0x08 // PALIGNR XMM11, XMM12, 0x8 /* m[15], m[6] */; ; ; ; ; - - LOAD_SHUFFLE - G1 - G2 - DIAGONALIZE - - // LOAD_MSG_ ##r ##_3 / ##_4(b0, b1); (X12 is temp register) - MOVOU 0(DX), X12 // X12 = m[0]+ m[1] - MOVOU 32(DX), X13 // X13 = m[4]+ m[5] - MOVOU 80(DX), X14 // X14 = m[10]+m[11] - MOVOU X12, X8 - LONG $0x3a0f4566; WORD $0xc40f; BYTE $0x08 // PALIGNR XMM8, XMM12, 0x8 /* m[1], m[0] */ - MOVOU X14, X9 - LONG $0x6d0f4566; BYTE $0xcd // PUNPCKHQDQ XMM9, XMM13 /* m[11], m[5] */ - MOVOU 16(DX), X12 // X12 = m[2]+ m[3] - MOVOU 48(DX), X11 // X11 = m[6]+ m[7] - MOVOU 96(DX), X10 // X10 = m[12]+m[13] - LONG $0x6c0f4566; BYTE $0xd4 // PUNPCKLQDQ XMM10, XMM12 /* m[12], m[2] */ - LONG $0x6d0f4566; BYTE $0xdc // PUNPCKHQDQ XMM11, XMM12 /* m[7], m[3] */ - - LOAD_SHUFFLE - G1 - G2 - UNDIAGONALIZE - - // Reload digest (most current value store in &out) - MOVQ out+144(FP), SI // SI: &in - MOVOU 0(SI), X12 // X12 = in[0]+in[1] /* row1l = LOAD( &S->h[0] ); */ - MOVOU 16(SI), X13 // X13 = in[2]+in[3] /* row1h = LOAD( &S->h[2] ); */ - MOVOU 32(SI), X14 // X14 = in[4]+in[5] /* row2l = LOAD( &S->h[4] ); */ - MOVOU 48(SI), X15 // X15 = in[6]+in[7] /* row2h = LOAD( &S->h[6] ); */ - - // Final computations and prepare for storing - PXOR X4, X0 // X0 = X0 ^ X4 /* row1l = _mm_xor_si128( row3l, row1l ); */ - PXOR X5, X1 // X1 = X1 ^ X5 /* row1h = _mm_xor_si128( row3h, row1h ); */ - PXOR X12, X0 // X0 = X0 ^ X12 /* STORE( &S->h[0], _mm_xor_si128( LOAD( &S->h[0] ), row1l ) ); */ - PXOR X13, X1 // X1 = X1 ^ X13 /* STORE( &S->h[2], _mm_xor_si128( LOAD( &S->h[2] ), row1h ) ); */ - PXOR X6, X2 // X2 = X2 ^ X6 /* row2l = _mm_xor_si128( row4l, row2l ); */ - PXOR X7, X3 // X3 = X3 ^ X7 /* row2h = _mm_xor_si128( row4h, row2h ); */ - PXOR X14, X2 // X2 = X2 ^ X14 /* STORE( &S->h[4], _mm_xor_si128( LOAD( &S->h[4] ), row2l ) ); */ - PXOR X15, X3 // X3 = X3 ^ X15 /* STORE( &S->h[6], _mm_xor_si128( LOAD( &S->h[6] ), row2h ) ); */ - - // Store digest into &out - MOVQ out+144(FP), SI // SI: &out - MOVOU X0, 0(SI) // out[0]+out[1] = X0 - MOVOU X1, 16(SI) // out[2]+out[3] = X1 - MOVOU X2, 32(SI) // out[4]+out[5] = X2 - MOVOU X3, 48(SI) // out[6]+out[7] = X3 - - // Increment message pointer and check if there's more to do - ADDQ $128, DX // message += 128 - SUBQ $1, R8 - JNZ loop - -complete: - RET diff --git a/vendor/github.com/minio/blake2b-simd/compress_generic.go b/vendor/github.com/minio/blake2b-simd/compress_generic.go deleted file mode 100644 index e9e16e8b9..000000000 --- a/vendor/github.com/minio/blake2b-simd/compress_generic.go +++ /dev/null @@ -1,1419 +0,0 @@ -// Written in 2012 by Dmitry Chestnykh. -// -// To the extent possible under law, the author have dedicated all copyright -// and related and neighboring rights to this software to the public domain -// worldwide. This software is distributed without any warranty. -// http://creativecommons.org/publicdomain/zero/1.0/ - -package blake2b - -func compressGeneric(d *digest, p []uint8) { - h0, h1, h2, h3, h4, h5, h6, h7 := d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] - - for len(p) >= BlockSize { - // Increment counter. - d.t[0] += BlockSize - if d.t[0] < BlockSize { - d.t[1]++ - } - // Initialize compression function. - v0, v1, v2, v3, v4, v5, v6, v7 := h0, h1, h2, h3, h4, h5, h6, h7 - v8 := iv[0] - v9 := iv[1] - v10 := iv[2] - v11 := iv[3] - v12 := iv[4] ^ d.t[0] - v13 := iv[5] ^ d.t[1] - v14 := iv[6] ^ d.f[0] - v15 := iv[7] ^ d.f[1] - - j := 0 - var m [16]uint64 - for i := range m { - m[i] = uint64(p[j]) | uint64(p[j+1])<<8 | uint64(p[j+2])<<16 | - uint64(p[j+3])<<24 | uint64(p[j+4])<<32 | uint64(p[j+5])<<40 | - uint64(p[j+6])<<48 | uint64(p[j+7])<<56 - j += 8 - } - - // Round 1. - v0 += m[0] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[2] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[4] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[6] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[5] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[7] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[3] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[1] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[8] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[10] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[12] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[14] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[13] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[15] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[11] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[9] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 2. - v0 += m[14] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[4] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[9] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[13] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[15] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[6] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[8] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[10] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[1] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[0] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[11] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[5] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[7] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[3] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[2] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[12] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 3. - v0 += m[11] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[12] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[5] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[15] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[2] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[13] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[0] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[8] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[10] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[3] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[7] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[9] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[1] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[4] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[6] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[14] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 4. - v0 += m[7] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[3] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[13] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[11] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[12] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[14] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[1] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[9] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[2] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[5] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[4] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[15] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[0] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[8] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[10] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[6] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 5. - v0 += m[9] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[5] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[2] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[10] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[4] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[15] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[7] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[0] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[14] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[11] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[6] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[3] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[8] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[13] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[12] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[1] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 6. - v0 += m[2] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[6] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[0] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[8] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[11] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[3] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[10] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[12] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[4] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[7] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[15] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[1] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[14] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[9] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[5] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[13] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 7. - v0 += m[12] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[1] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[14] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[4] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[13] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[10] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[15] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[5] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[0] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[6] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[9] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[8] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[2] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[11] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[3] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[7] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 8. - v0 += m[13] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[7] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[12] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[3] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[1] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[9] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[14] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[11] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[5] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[15] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[8] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[2] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[6] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[10] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[4] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[0] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 9. - v0 += m[6] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[14] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[11] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[0] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[3] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[8] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[9] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[15] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[12] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[13] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[1] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[10] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[4] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[5] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[7] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[2] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 10. - v0 += m[10] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[8] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[7] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[1] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[6] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[5] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[4] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[2] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[15] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[9] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[3] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[13] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[12] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[0] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[14] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[11] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 11. - v0 += m[0] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[2] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[4] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[6] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[5] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[7] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[3] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[1] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[8] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[10] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[12] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[14] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[13] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[15] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[11] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[9] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - // Round 12. - v0 += m[14] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-32) | v12>>32 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-24) | v4>>24 - v1 += m[4] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-32) | v13>>32 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-24) | v5>>24 - v2 += m[9] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-32) | v14>>32 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-24) | v6>>24 - v3 += m[13] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-32) | v15>>32 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-24) | v7>>24 - v2 += m[15] - v2 += v6 - v14 ^= v2 - v14 = v14<<(64-16) | v14>>16 - v10 += v14 - v6 ^= v10 - v6 = v6<<(64-63) | v6>>63 - v3 += m[6] - v3 += v7 - v15 ^= v3 - v15 = v15<<(64-16) | v15>>16 - v11 += v15 - v7 ^= v11 - v7 = v7<<(64-63) | v7>>63 - v1 += m[8] - v1 += v5 - v13 ^= v1 - v13 = v13<<(64-16) | v13>>16 - v9 += v13 - v5 ^= v9 - v5 = v5<<(64-63) | v5>>63 - v0 += m[10] - v0 += v4 - v12 ^= v0 - v12 = v12<<(64-16) | v12>>16 - v8 += v12 - v4 ^= v8 - v4 = v4<<(64-63) | v4>>63 - v0 += m[1] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-32) | v15>>32 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-24) | v5>>24 - v1 += m[0] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-32) | v12>>32 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-24) | v6>>24 - v2 += m[11] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-32) | v13>>32 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-24) | v7>>24 - v3 += m[5] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-32) | v14>>32 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-24) | v4>>24 - v2 += m[7] - v2 += v7 - v13 ^= v2 - v13 = v13<<(64-16) | v13>>16 - v8 += v13 - v7 ^= v8 - v7 = v7<<(64-63) | v7>>63 - v3 += m[3] - v3 += v4 - v14 ^= v3 - v14 = v14<<(64-16) | v14>>16 - v9 += v14 - v4 ^= v9 - v4 = v4<<(64-63) | v4>>63 - v1 += m[2] - v1 += v6 - v12 ^= v1 - v12 = v12<<(64-16) | v12>>16 - v11 += v12 - v6 ^= v11 - v6 = v6<<(64-63) | v6>>63 - v0 += m[12] - v0 += v5 - v15 ^= v0 - v15 = v15<<(64-16) | v15>>16 - v10 += v15 - v5 ^= v10 - v5 = v5<<(64-63) | v5>>63 - - h0 ^= v0 ^ v8 - h1 ^= v1 ^ v9 - h2 ^= v2 ^ v10 - h3 ^= v3 ^ v11 - h4 ^= v4 ^ v12 - h5 ^= v5 ^ v13 - h6 ^= v6 ^ v14 - h7 ^= v7 ^ v15 - - p = p[BlockSize:] - } - d.h[0], d.h[1], d.h[2], d.h[3], d.h[4], d.h[5], d.h[6], d.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 -} diff --git a/vendor/github.com/minio/blake2b-simd/cpuid.go b/vendor/github.com/minio/blake2b-simd/cpuid.go deleted file mode 100644 index a9f95508e..000000000 --- a/vendor/github.com/minio/blake2b-simd/cpuid.go +++ /dev/null @@ -1,60 +0,0 @@ -// +build 386,!gccgo amd64,!gccgo - -// Copyright 2016 Frank Wessels -// -// 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. -// - -package blake2b - -func cpuid(op uint32) (eax, ebx, ecx, edx uint32) -func cpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) -func xgetbv(index uint32) (eax, edx uint32) - -// True when SIMD instructions are available. -var avx2 = haveAVX2() -var avx = haveAVX() -var ssse3 = haveSSSE3() - -// haveAVX returns true when there is AVX support -func haveAVX() bool { - _, _, c, _ := cpuid(1) - - // Check XGETBV, OXSAVE and AVX bits - if c&(1<<26) != 0 && c&(1<<27) != 0 && c&(1<<28) != 0 { - // Check for OS support - eax, _ := xgetbv(0) - return (eax & 0x6) == 0x6 - } - return false -} - -// haveAVX2 returns true when there is AVX2 support -func haveAVX2() bool { - mfi, _, _, _ := cpuid(0) - - // Check AVX2, AVX2 requires OS support, but BMI1/2 don't. - if mfi >= 7 && haveAVX() { - _, ebx, _, _ := cpuidex(7, 0) - return (ebx & 0x00000020) != 0 - } - return false -} - -// haveSSSE3 returns true when there is SSSE3 support -func haveSSSE3() bool { - - _, _, c, _ := cpuid(1) - - return (c & 0x00000200) != 0 -} diff --git a/vendor/github.com/minio/blake2b-simd/cpuid_386.s b/vendor/github.com/minio/blake2b-simd/cpuid_386.s deleted file mode 100644 index fa38814ec..000000000 --- a/vendor/github.com/minio/blake2b-simd/cpuid_386.s +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// +build 386,!gccgo - -// func cpuid(op uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuid(SB), 7, $0 - XORL CX, CX - MOVL op+0(FP), AX - CPUID - MOVL AX, eax+4(FP) - MOVL BX, ebx+8(FP) - MOVL CX, ecx+12(FP) - MOVL DX, edx+16(FP) - RET - -// func cpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuidex(SB), 7, $0 - MOVL op+0(FP), AX - MOVL op2+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func xgetbv(index uint32) (eax, edx uint32) -TEXT ·xgetbv(SB), 7, $0 - MOVL index+0(FP), CX - BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV - MOVL AX, eax+4(FP) - MOVL DX, edx+8(FP) - RET diff --git a/vendor/github.com/minio/blake2b-simd/cpuid_amd64.s b/vendor/github.com/minio/blake2b-simd/cpuid_amd64.s deleted file mode 100644 index fb45a6560..000000000 --- a/vendor/github.com/minio/blake2b-simd/cpuid_amd64.s +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// +build amd64,!gccgo - -// func cpuid(op uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuid(SB), 7, $0 - XORQ CX, CX - MOVL op+0(FP), AX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - - -// func cpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuidex(SB), 7, $0 - MOVL op+0(FP), AX - MOVL op2+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func xgetbv(index uint32) (eax, edx uint32) -TEXT ·xgetbv(SB), 7, $0 - MOVL index+0(FP), CX - BYTE $0x0f; BYTE $0x01; BYTE $0xd0 // XGETBV - MOVL AX, eax+8(FP) - MOVL DX, edx+12(FP) - RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b.go b/vendor/golang.org/x/crypto/blake2b/blake2b.go new file mode 100644 index 000000000..fa9e48e31 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b.go @@ -0,0 +1,194 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package blake2b implements the BLAKE2b hash algorithm as +// defined in RFC 7693. +package blake2b + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + // The blocksize of BLAKE2b in bytes. + BlockSize = 128 + // The hash size of BLAKE2b-512 in bytes. + Size = 64 + // The hash size of BLAKE2b-384 in bytes. + Size384 = 48 + // The hash size of BLAKE2b-256 in bytes. + Size256 = 32 +) + +var ( + useAVX2 bool + useAVX bool + useSSE4 bool +) + +var errKeySize = errors.New("blake2b: invalid key size") + +var iv = [8]uint64{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +// Sum512 returns the BLAKE2b-512 checksum of the data. +func Sum512(data []byte) [Size]byte { + var sum [Size]byte + checkSum(&sum, Size, data) + return sum +} + +// Sum384 returns the BLAKE2b-384 checksum of the data. +func Sum384(data []byte) [Size384]byte { + var sum [Size]byte + var sum384 [Size384]byte + checkSum(&sum, Size384, data) + copy(sum384[:], sum[:Size384]) + return sum384 +} + +// Sum256 returns the BLAKE2b-256 checksum of the data. +func Sum256(data []byte) [Size256]byte { + var sum [Size]byte + var sum256 [Size256]byte + checkSum(&sum, Size256, data) + copy(sum256[:], sum[:Size256]) + return sum256 +} + +// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil +// key turns the hash into a MAC. The key must between zero and 64 bytes long. +func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) } + +// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil +// key turns the hash into a MAC. The key must between zero and 64 bytes long. +func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) } + +// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil +// key turns the hash into a MAC. The key must between zero and 64 bytes long. +func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } + +func newDigest(hashSize int, key []byte) (*digest, error) { + if len(key) > Size { + return nil, errKeySize + } + d := &digest{ + size: hashSize, + keyLen: len(key), + } + copy(d.key[:], key) + d.Reset() + return d, nil +} + +func checkSum(sum *[Size]byte, hashSize int, data []byte) { + h := iv + h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24) + var c [2]uint64 + + if length := len(data); length > BlockSize { + n := length &^ (BlockSize - 1) + if length == n { + n -= BlockSize + } + hashBlocks(&h, &c, 0, data[:n]) + data = data[n:] + } + + var block [BlockSize]byte + offset := copy(block[:], data) + remaining := uint64(BlockSize - offset) + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) + + for i, v := range h[:(hashSize+7)/8] { + binary.LittleEndian.PutUint64(sum[8*i:], v) + } +} + +type digest struct { + h [8]uint64 + c [2]uint64 + size int + block [BlockSize]byte + offset int + + key [BlockSize]byte + keyLen int +} + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Size() int { return d.size } + +func (d *digest) Reset() { + d.h = iv + d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24) + d.offset, d.c[0], d.c[1] = 0, 0, 0 + if d.keyLen > 0 { + d.block = d.key + d.offset = BlockSize + } +} + +func (d *digest) Write(p []byte) (n int, err error) { + n = len(p) + + if d.offset > 0 { + remaining := BlockSize - d.offset + if n <= remaining { + d.offset += copy(d.block[d.offset:], p) + return + } + copy(d.block[d.offset:], p[:remaining]) + hashBlocks(&d.h, &d.c, 0, d.block[:]) + d.offset = 0 + p = p[remaining:] + } + + if length := len(p); length > BlockSize { + nn := length &^ (BlockSize - 1) + if length == nn { + nn -= BlockSize + } + hashBlocks(&d.h, &d.c, 0, p[:nn]) + p = p[nn:] + } + + if len(p) > 0 { + d.offset += copy(d.block[:], p) + } + + return +} + +func (d *digest) Sum(b []byte) []byte { + var block [BlockSize]byte + copy(block[:], d.block[:d.offset]) + remaining := uint64(BlockSize - d.offset) + + c := d.c + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + h := d.h + hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) + + var sum [Size]byte + for i, v := range h[:(d.size+7)/8] { + binary.LittleEndian.PutUint64(sum[8*i:], v) + } + + return append(b, sum[:d.size]...) +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go new file mode 100644 index 000000000..8c41cf6c7 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go @@ -0,0 +1,43 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7,amd64,!gccgo,!appengine + +package blake2b + +func init() { + useAVX2 = supportsAVX2() + useAVX = supportsAVX() + useSSE4 = supportsSSE4() +} + +//go:noescape +func supportsSSE4() bool + +//go:noescape +func supportsAVX() bool + +//go:noescape +func supportsAVX2() bool + +//go:noescape +func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +//go:noescape +func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +//go:noescape +func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + if useAVX2 { + hashBlocksAVX2(h, c, flag, blocks) + } else if useAVX { + hashBlocksAVX(h, c, flag, blocks) + } else if useSSE4 { + hashBlocksSSE4(h, c, flag, blocks) + } else { + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s new file mode 100644 index 000000000..784bce6a9 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s @@ -0,0 +1,762 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7,amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16 + +#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 +#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 +#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e +#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 +#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 + +#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \ + VPADDQ m0, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFD $-79, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPSHUFB c40, Y1, Y1; \ + VPADDQ m1, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFB c48, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPADDQ Y1, Y1, t; \ + VPSRLQ $63, Y1, Y1; \ + VPXOR t, Y1, Y1; \ + VPERMQ_0x39_Y1_Y1; \ + VPERMQ_0x4E_Y2_Y2; \ + VPERMQ_0x93_Y3_Y3; \ + VPADDQ m2, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFD $-79, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPSHUFB c40, Y1, Y1; \ + VPADDQ m3, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFB c48, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPADDQ Y1, Y1, t; \ + VPSRLQ $63, Y1, Y1; \ + VPXOR t, Y1, Y1; \ + VPERMQ_0x39_Y3_Y3; \ + VPERMQ_0x4E_Y2_Y2; \ + VPERMQ_0x93_Y1_Y1 + +#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E +#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26 +#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E +#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36 +#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E + +#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n +#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n +#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n +#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n +#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n + +#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01 +#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01 +#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01 +#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01 +#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01 + +#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01 + +#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8 +#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01 + +// load msg: Y12 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \ + VMOVQ_SI_X12(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X12(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y12, Y12 + +// load msg: Y13 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \ + VMOVQ_SI_X13(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X13(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y13, Y13 + +// load msg: Y14 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \ + VMOVQ_SI_X14(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X14(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y14, Y14 + +// load msg: Y15 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \ + VMOVQ_SI_X15(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X15(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \ + VMOVQ_SI_X12_0; \ + VMOVQ_SI_X11(4*8); \ + VPINSRQ_1_SI_X12(2*8); \ + VPINSRQ_1_SI_X11(6*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \ + LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \ + LOAD_MSG_AVX2_Y15(9, 11, 13, 15) + +#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \ + LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \ + LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \ + VMOVQ_SI_X11(11*8); \ + VPSHUFD $0x4E, 0*8(SI), X14; \ + VPINSRQ_1_SI_X11(5*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + LOAD_MSG_AVX2_Y15(12, 2, 7, 3) + +#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \ + VMOVQ_SI_X11(5*8); \ + VMOVDQU 11*8(SI), X12; \ + VPINSRQ_1_SI_X11(15*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + VMOVQ_SI_X13(8*8); \ + VMOVQ_SI_X11(2*8); \ + VPINSRQ_1_SI_X13_0; \ + VPINSRQ_1_SI_X11(13*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \ + LOAD_MSG_AVX2_Y15(14, 6, 1, 4) + +#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \ + LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \ + LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \ + LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \ + VMOVQ_SI_X15(6*8); \ + VMOVQ_SI_X11_0; \ + VPINSRQ_1_SI_X15(10*8); \ + VPINSRQ_1_SI_X11(8*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \ + LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \ + VMOVQ_SI_X13_0; \ + VMOVQ_SI_X11(4*8); \ + VPINSRQ_1_SI_X13(7*8); \ + VPINSRQ_1_SI_X11(15*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \ + LOAD_MSG_AVX2_Y15(1, 12, 8, 13) + +#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X11_0; \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X11(8*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \ + LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \ + LOAD_MSG_AVX2_Y15(13, 5, 14, 9) + +#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \ + LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \ + LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \ + VMOVQ_SI_X14_0; \ + VPSHUFD $0x4E, 8*8(SI), X11; \ + VPINSRQ_1_SI_X14(6*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + LOAD_MSG_AVX2_Y15(7, 3, 2, 11) + +#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \ + LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \ + LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \ + LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \ + VMOVQ_SI_X15_0; \ + VMOVQ_SI_X11(6*8); \ + VPINSRQ_1_SI_X15(4*8); \ + VPINSRQ_1_SI_X11(10*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \ + VMOVQ_SI_X12(6*8); \ + VMOVQ_SI_X11(11*8); \ + VPINSRQ_1_SI_X12(14*8); \ + VPINSRQ_1_SI_X11_0; \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \ + VMOVQ_SI_X11(1*8); \ + VMOVDQU 12*8(SI), X14; \ + VPINSRQ_1_SI_X11(10*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + VMOVQ_SI_X15(2*8); \ + VMOVDQU 4*8(SI), X11; \ + VPINSRQ_1_SI_X15(7*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \ + LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \ + VMOVQ_SI_X13(2*8); \ + VPSHUFD $0x4E, 5*8(SI), X11; \ + VPINSRQ_1_SI_X13(4*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \ + VMOVQ_SI_X15(11*8); \ + VMOVQ_SI_X11(12*8); \ + VPINSRQ_1_SI_X15(14*8); \ + VPINSRQ_1_SI_X11_0; \ + VINSERTI128 $1, X11, Y15, Y15 + +// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, DX + MOVQ SP, R9 + ADDQ $31, R9 + ANDQ $~31, R9 + MOVQ R9, SP + + MOVQ CX, 16(SP) + XORQ CX, CX + MOVQ CX, 24(SP) + + VMOVDQU ·AVX2_c40<>(SB), Y4 + VMOVDQU ·AVX2_c48<>(SB), Y5 + + VMOVDQU 0(AX), Y8 + VMOVDQU 32(AX), Y9 + VMOVDQU ·AVX2_iv0<>(SB), Y6 + VMOVDQU ·AVX2_iv1<>(SB), Y7 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + MOVQ R9, 8(SP) + +loop: + ADDQ $128, R8 + MOVQ R8, 0(SP) + CMPQ R8, $128 + JGE noinc + INCQ R9 + MOVQ R9, 8(SP) + +noinc: + VMOVDQA Y8, Y0 + VMOVDQA Y9, Y1 + VMOVDQA Y6, Y2 + VPXOR 0(SP), Y7, Y3 + + LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() + VMOVDQA Y12, 32(SP) + VMOVDQA Y13, 64(SP) + VMOVDQA Y14, 96(SP) + VMOVDQA Y15, 128(SP) + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() + VMOVDQA Y12, 160(SP) + VMOVDQA Y13, 192(SP) + VMOVDQA Y14, 224(SP) + VMOVDQA Y15, 256(SP) + + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + + ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5) + ROUND_AVX2(160(SP), 192(SP), 224(SP), 256(SP), Y10, Y4, Y5) + + VPXOR Y0, Y8, Y8 + VPXOR Y1, Y9, Y9 + VPXOR Y2, Y8, Y8 + VPXOR Y3, Y9, Y9 + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + + VMOVDQU Y8, 0(AX) + VMOVDQU Y9, 32(AX) + VZEROUPPER + + MOVQ DX, SP + RET + +#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA +#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB +#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF +#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD +#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE + +#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7 +#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF +#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7 +#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF +#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7 +#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7 +#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF +#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF + +#define SHUFFLE_AVX() \ + VMOVDQA X6, X13; \ + VMOVDQA X2, X14; \ + VMOVDQA X4, X6; \ + VPUNPCKLQDQ_X13_X13_X15; \ + VMOVDQA X5, X4; \ + VMOVDQA X6, X5; \ + VPUNPCKHQDQ_X15_X7_X6; \ + VPUNPCKLQDQ_X7_X7_X15; \ + VPUNPCKHQDQ_X15_X13_X7; \ + VPUNPCKLQDQ_X3_X3_X15; \ + VPUNPCKHQDQ_X15_X2_X2; \ + VPUNPCKLQDQ_X14_X14_X15; \ + VPUNPCKHQDQ_X15_X3_X3; \ + +#define SHUFFLE_AVX_INV() \ + VMOVDQA X2, X13; \ + VMOVDQA X4, X14; \ + VPUNPCKLQDQ_X2_X2_X15; \ + VMOVDQA X5, X4; \ + VPUNPCKHQDQ_X15_X3_X2; \ + VMOVDQA X14, X5; \ + VPUNPCKLQDQ_X3_X3_X15; \ + VMOVDQA X6, X14; \ + VPUNPCKHQDQ_X15_X13_X3; \ + VPUNPCKLQDQ_X7_X7_X15; \ + VPUNPCKHQDQ_X15_X6_X6; \ + VPUNPCKLQDQ_X14_X14_X15; \ + VPUNPCKHQDQ_X15_X7_X7; \ + +#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ + VPADDQ m0, v0, v0; \ + VPADDQ v2, v0, v0; \ + VPADDQ m1, v1, v1; \ + VPADDQ v3, v1, v1; \ + VPXOR v0, v6, v6; \ + VPXOR v1, v7, v7; \ + VPSHUFD $-79, v6, v6; \ + VPSHUFD $-79, v7, v7; \ + VPADDQ v6, v4, v4; \ + VPADDQ v7, v5, v5; \ + VPXOR v4, v2, v2; \ + VPXOR v5, v3, v3; \ + VPSHUFB c40, v2, v2; \ + VPSHUFB c40, v3, v3; \ + VPADDQ m2, v0, v0; \ + VPADDQ v2, v0, v0; \ + VPADDQ m3, v1, v1; \ + VPADDQ v3, v1, v1; \ + VPXOR v0, v6, v6; \ + VPXOR v1, v7, v7; \ + VPSHUFB c48, v6, v6; \ + VPSHUFB c48, v7, v7; \ + VPADDQ v6, v4, v4; \ + VPADDQ v7, v5, v5; \ + VPXOR v4, v2, v2; \ + VPXOR v5, v3, v3; \ + VPADDQ v2, v2, t0; \ + VPSRLQ $63, v2, v2; \ + VPXOR t0, v2, v2; \ + VPADDQ v3, v3, t0; \ + VPSRLQ $63, v3, v3; \ + VPXOR t0, v3, v3 + +// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7) +// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0 +#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \ + VMOVQ_SI_X12(i0*8); \ + VMOVQ_SI_X13(i2*8); \ + VMOVQ_SI_X14(i4*8); \ + VMOVQ_SI_X15(i6*8); \ + VPINSRQ_1_SI_X12(i1*8); \ + VPINSRQ_1_SI_X13(i3*8); \ + VPINSRQ_1_SI_X14(i5*8); \ + VPINSRQ_1_SI_X15(i7*8) + +// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7) +#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \ + VMOVQ_SI_X12_0; \ + VMOVQ_SI_X13(4*8); \ + VMOVQ_SI_X14(1*8); \ + VMOVQ_SI_X15(5*8); \ + VPINSRQ_1_SI_X12(2*8); \ + VPINSRQ_1_SI_X13(6*8); \ + VPINSRQ_1_SI_X14(3*8); \ + VPINSRQ_1_SI_X15(7*8) + +// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3) +#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \ + VPSHUFD $0x4E, 0*8(SI), X12; \ + VMOVQ_SI_X13(11*8); \ + VMOVQ_SI_X14(12*8); \ + VMOVQ_SI_X15(7*8); \ + VPINSRQ_1_SI_X13(5*8); \ + VPINSRQ_1_SI_X14(2*8); \ + VPINSRQ_1_SI_X15(3*8) + +// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13) +#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \ + VMOVDQU 11*8(SI), X12; \ + VMOVQ_SI_X13(5*8); \ + VMOVQ_SI_X14(8*8); \ + VMOVQ_SI_X15(2*8); \ + VPINSRQ_1_SI_X13(15*8); \ + VPINSRQ_1_SI_X14_0; \ + VPINSRQ_1_SI_X15(13*8) + +// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8) +#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X13(4*8); \ + VMOVQ_SI_X14(6*8); \ + VMOVQ_SI_X15_0; \ + VPINSRQ_1_SI_X12(5*8); \ + VPINSRQ_1_SI_X13(15*8); \ + VPINSRQ_1_SI_X14(10*8); \ + VPINSRQ_1_SI_X15(8*8) + +// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15) +#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \ + VMOVQ_SI_X12(9*8); \ + VMOVQ_SI_X13(2*8); \ + VMOVQ_SI_X14_0; \ + VMOVQ_SI_X15(4*8); \ + VPINSRQ_1_SI_X12(5*8); \ + VPINSRQ_1_SI_X13(10*8); \ + VPINSRQ_1_SI_X14(7*8); \ + VPINSRQ_1_SI_X15(15*8) + +// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3) +#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X13_0; \ + VMOVQ_SI_X14(12*8); \ + VMOVQ_SI_X15(11*8); \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X13(8*8); \ + VPINSRQ_1_SI_X14(10*8); \ + VPINSRQ_1_SI_X15(3*8) + +// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11) +#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \ + MOVQ 0*8(SI), X12; \ + VPSHUFD $0x4E, 8*8(SI), X13; \ + MOVQ 7*8(SI), X14; \ + MOVQ 2*8(SI), X15; \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X14(3*8); \ + VPINSRQ_1_SI_X15(11*8) + +// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8) +#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \ + MOVQ 6*8(SI), X12; \ + MOVQ 11*8(SI), X13; \ + MOVQ 15*8(SI), X14; \ + MOVQ 3*8(SI), X15; \ + VPINSRQ_1_SI_X12(14*8); \ + VPINSRQ_1_SI_X13_0; \ + VPINSRQ_1_SI_X14(9*8); \ + VPINSRQ_1_SI_X15(8*8) + +// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10) +#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \ + MOVQ 5*8(SI), X12; \ + MOVQ 8*8(SI), X13; \ + MOVQ 0*8(SI), X14; \ + MOVQ 6*8(SI), X15; \ + VPINSRQ_1_SI_X12(15*8); \ + VPINSRQ_1_SI_X13(2*8); \ + VPINSRQ_1_SI_X14(4*8); \ + VPINSRQ_1_SI_X15(10*8) + +// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5) +#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \ + VMOVDQU 12*8(SI), X12; \ + MOVQ 1*8(SI), X13; \ + MOVQ 2*8(SI), X14; \ + VPINSRQ_1_SI_X13(10*8); \ + VPINSRQ_1_SI_X14(7*8); \ + VMOVDQU 4*8(SI), X15 + +// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0) +#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \ + MOVQ 15*8(SI), X12; \ + MOVQ 3*8(SI), X13; \ + MOVQ 11*8(SI), X14; \ + MOVQ 12*8(SI), X15; \ + VPINSRQ_1_SI_X12(9*8); \ + VPINSRQ_1_SI_X13(13*8); \ + VPINSRQ_1_SI_X14(14*8); \ + VPINSRQ_1_SI_X15_0 + +// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, BP + MOVQ SP, R9 + ADDQ $15, R9 + ANDQ $~15, R9 + MOVQ R9, SP + + VMOVDQU ·AVX_c40<>(SB), X0 + VMOVDQU ·AVX_c48<>(SB), X1 + VMOVDQA X0, X8 + VMOVDQA X1, X9 + + VMOVDQU ·AVX_iv3<>(SB), X0 + VMOVDQA X0, 0(SP) + XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0) + + VMOVDQU 0(AX), X10 + VMOVDQU 16(AX), X11 + VMOVDQU 32(AX), X2 + VMOVDQU 48(AX), X3 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + +loop: + ADDQ $128, R8 + CMPQ R8, $128 + JGE noinc + INCQ R9 + +noinc: + VMOVQ_R8_X15 + VPINSRQ_1_R9_X15 + + VMOVDQA X10, X0 + VMOVDQA X11, X1 + VMOVDQU ·AVX_iv0<>(SB), X4 + VMOVDQU ·AVX_iv1<>(SB), X5 + VMOVDQU ·AVX_iv2<>(SB), X6 + + VPXOR X15, X6, X6 + VMOVDQA 0(SP), X7 + + LOAD_MSG_AVX_0_2_4_6_1_3_5_7() + VMOVDQA X12, 16(SP) + VMOVDQA X13, 32(SP) + VMOVDQA X14, 48(SP) + VMOVDQA X15, 64(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15) + VMOVDQA X12, 80(SP) + VMOVDQA X13, 96(SP) + VMOVDQA X14, 112(SP) + VMOVDQA X15, 128(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6) + VMOVDQA X12, 144(SP) + VMOVDQA X13, 160(SP) + VMOVDQA X14, 176(SP) + VMOVDQA X15, 192(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_1_0_11_5_12_2_7_3() + VMOVDQA X12, 208(SP) + VMOVDQA X13, 224(SP) + VMOVDQA X14, 240(SP) + VMOVDQA X15, 256(SP) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_11_12_5_15_8_0_2_13() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_2_5_4_15_6_10_0_8() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_9_5_2_10_0_7_4_15() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_2_6_0_8_12_10_11_3() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_0_6_9_8_7_3_2_11() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_5_15_8_2_0_4_6_10() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_6_14_11_0_15_9_3_8() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_12_13_1_10_2_7_4_5() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_15_9_3_13_11_14_12_0() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9) + SHUFFLE_AVX() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9) + SHUFFLE_AVX_INV() + + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9) + SHUFFLE_AVX() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9) + SHUFFLE_AVX_INV() + + VMOVDQU 32(AX), X14 + VMOVDQU 48(AX), X15 + VPXOR X0, X10, X10 + VPXOR X1, X11, X11 + VPXOR X2, X14, X14 + VPXOR X3, X15, X15 + VPXOR X4, X10, X10 + VPXOR X5, X11, X11 + VPXOR X6, X14, X2 + VPXOR X7, X15, X3 + VMOVDQU X2, 32(AX) + VMOVDQU X3, 48(AX) + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + VMOVDQU X10, 0(AX) + VMOVDQU X11, 16(AX) + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + VZEROUPPER + + MOVQ BP, SP + RET + +// func supportsAVX2() bool +TEXT ·supportsAVX2(SB), 4, $0-1 + MOVQ runtime·support_avx2(SB), AX + MOVB AX, ret+0(FP) + RET + +// func supportsAVX() bool +TEXT ·supportsAVX(SB), 4, $0-1 + MOVQ runtime·support_avx(SB), AX + MOVB AX, ret+0(FP) + RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go new file mode 100644 index 000000000..2ab7c30fc --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go @@ -0,0 +1,25 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.7,amd64,!gccgo,!appengine + +package blake2b + +func init() { + useSSE4 = supportsSSE4() +} + +//go:noescape +func supportsSSE4() bool + +//go:noescape +func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + if useSSE4 { + hashBlocksSSE4(h, c, flag, blocks) + } else { + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s new file mode 100644 index 000000000..64530740b --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s @@ -0,0 +1,290 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b +DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b +DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 +GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16 + +DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 + +#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v6, t1; \ + PUNPCKLQDQ v6, t2; \ + PUNPCKHQDQ v7, v6; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ v7, t2; \ + MOVO t1, v7; \ + MOVO v2, t1; \ + PUNPCKHQDQ t2, v7; \ + PUNPCKLQDQ v3, t2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v3 + +#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v2, t1; \ + PUNPCKLQDQ v2, t2; \ + PUNPCKHQDQ v3, v2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ v3, t2; \ + MOVO t1, v3; \ + MOVO v6, t1; \ + PUNPCKHQDQ t2, v3; \ + PUNPCKLQDQ v7, t2; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v7 + +#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ + PADDQ m0, v0; \ + PADDQ m1, v1; \ + PADDQ v2, v0; \ + PADDQ v3, v1; \ + PXOR v0, v6; \ + PXOR v1, v7; \ + PSHUFD $0xB1, v6, v6; \ + PSHUFD $0xB1, v7, v7; \ + PADDQ v6, v4; \ + PADDQ v7, v5; \ + PXOR v4, v2; \ + PXOR v5, v3; \ + PSHUFB c40, v2; \ + PSHUFB c40, v3; \ + PADDQ m2, v0; \ + PADDQ m3, v1; \ + PADDQ v2, v0; \ + PADDQ v3, v1; \ + PXOR v0, v6; \ + PXOR v1, v7; \ + PSHUFB c48, v6; \ + PSHUFB c48, v7; \ + PADDQ v6, v4; \ + PADDQ v7, v5; \ + PXOR v4, v2; \ + PXOR v5, v3; \ + MOVOU v2, t0; \ + PADDQ v2, t0; \ + PSRLQ $63, v2; \ + PXOR t0, v2; \ + MOVOU v3, t0; \ + PADDQ v3, t0; \ + PSRLQ $63, v3; \ + PXOR t0, v3 + +#define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \ + MOVQ i0*8(src), m0; \ + PINSRQ $1, i1*8(src), m0; \ + MOVQ i2*8(src), m1; \ + PINSRQ $1, i3*8(src), m1; \ + MOVQ i4*8(src), m2; \ + PINSRQ $1, i5*8(src), m2; \ + MOVQ i6*8(src), m3; \ + PINSRQ $1, i7*8(src), m3 + +// func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, BP + MOVQ SP, R9 + ADDQ $15, R9 + ANDQ $~15, R9 + MOVQ R9, SP + + MOVOU ·iv3<>(SB), X0 + MOVO X0, 0(SP) + XORQ CX, 0(SP) // 0(SP) = ·iv3 ^ (CX || 0) + + MOVOU ·c40<>(SB), X13 + MOVOU ·c48<>(SB), X14 + + MOVOU 0(AX), X12 + MOVOU 16(AX), X15 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + +loop: + ADDQ $128, R8 + CMPQ R8, $128 + JGE noinc + INCQ R9 + +noinc: + MOVQ R8, X8 + PINSRQ $1, R9, X8 + + MOVO X12, X0 + MOVO X15, X1 + MOVOU 32(AX), X2 + MOVOU 48(AX), X3 + MOVOU ·iv0<>(SB), X4 + MOVOU ·iv1<>(SB), X5 + MOVOU ·iv2<>(SB), X6 + + PXOR X8, X6 + MOVO 0(SP), X7 + + LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7) + MOVO X8, 16(SP) + MOVO X9, 32(SP) + MOVO X10, 48(SP) + MOVO X11, 64(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15) + MOVO X8, 80(SP) + MOVO X9, 96(SP) + MOVO X10, 112(SP) + MOVO X11, 128(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6) + MOVO X8, 144(SP) + MOVO X9, 160(SP) + MOVO X10, 176(SP) + MOVO X11, 192(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3) + MOVO X8, 208(SP) + MOVO X9, 224(SP) + MOVO X10, 240(SP) + MOVO X11, 256(SP) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + MOVOU 32(AX), X10 + MOVOU 48(AX), X11 + PXOR X0, X12 + PXOR X1, X15 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X15 + PXOR X6, X10 + PXOR X7, X11 + MOVOU X10, 32(AX) + MOVOU X11, 48(AX) + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + MOVOU X12, 0(AX) + MOVOU X15, 16(AX) + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + + MOVQ BP, SP + RET + +// func supportsSSE4() bool +TEXT ·supportsSSE4(SB), 4, $0-1 + MOVL $1, AX + CPUID + SHRL $19, CX // Bit 19 indicates SSE4 support + ANDL $1, CX // CX != 0 if support SSE4 + MOVB CX, ret+0(FP) + RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go b/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go new file mode 100644 index 000000000..4bd2abc91 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go @@ -0,0 +1,179 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import "encoding/binary" + +// the precomputed values for BLAKE2b +// there are 12 16-byte arrays - one for each round +// the entries are calculated from the sigma constants. +var precomputed = [12][16]byte{ + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, + {11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, + {7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, + {9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, + {2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, + {12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, + {13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, + {6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, + {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0}, + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second +} + +func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + var m [16]uint64 + c0, c1 := c[0], c[1] + + for i := 0; i < len(blocks); { + c0 += BlockSize + if c0 < BlockSize { + c1++ + } + + v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7] + v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7] + v12 ^= c0 + v13 ^= c1 + v14 ^= flag + + for j := range m { + m[j] = binary.LittleEndian.Uint64(blocks[i:]) + i += 8 + } + + for j := range precomputed { + s := &(precomputed[j]) + + v0 += m[s[0]] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-32) | v12>>32 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-24) | v4>>24 + v1 += m[s[1]] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-32) | v13>>32 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-24) | v5>>24 + v2 += m[s[2]] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-32) | v14>>32 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-24) | v6>>24 + v3 += m[s[3]] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-32) | v15>>32 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-24) | v7>>24 + + v0 += m[s[4]] + v0 += v4 + v12 ^= v0 + v12 = v12<<(64-16) | v12>>16 + v8 += v12 + v4 ^= v8 + v4 = v4<<(64-63) | v4>>63 + v1 += m[s[5]] + v1 += v5 + v13 ^= v1 + v13 = v13<<(64-16) | v13>>16 + v9 += v13 + v5 ^= v9 + v5 = v5<<(64-63) | v5>>63 + v2 += m[s[6]] + v2 += v6 + v14 ^= v2 + v14 = v14<<(64-16) | v14>>16 + v10 += v14 + v6 ^= v10 + v6 = v6<<(64-63) | v6>>63 + v3 += m[s[7]] + v3 += v7 + v15 ^= v3 + v15 = v15<<(64-16) | v15>>16 + v11 += v15 + v7 ^= v11 + v7 = v7<<(64-63) | v7>>63 + + v0 += m[s[8]] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-32) | v15>>32 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-24) | v5>>24 + v1 += m[s[9]] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-32) | v12>>32 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-24) | v6>>24 + v2 += m[s[10]] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-32) | v13>>32 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-24) | v7>>24 + v3 += m[s[11]] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-32) | v14>>32 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-24) | v4>>24 + + v0 += m[s[12]] + v0 += v5 + v15 ^= v0 + v15 = v15<<(64-16) | v15>>16 + v10 += v15 + v5 ^= v10 + v5 = v5<<(64-63) | v5>>63 + v1 += m[s[13]] + v1 += v6 + v12 ^= v1 + v12 = v12<<(64-16) | v12>>16 + v11 += v12 + v6 ^= v11 + v6 = v6<<(64-63) | v6>>63 + v2 += m[s[14]] + v2 += v7 + v13 ^= v2 + v13 = v13<<(64-16) | v13>>16 + v8 += v13 + v7 ^= v8 + v7 = v7<<(64-63) | v7>>63 + v3 += m[s[15]] + v3 += v4 + v14 ^= v3 + v14 = v14<<(64-16) | v14>>16 + v9 += v14 + v4 ^= v9 + v4 = v4<<(64-63) | v4>>63 + + } + + h[0] ^= v0 ^ v8 + h[1] ^= v1 ^ v9 + h[2] ^= v2 ^ v10 + h[3] ^= v3 ^ v11 + h[4] ^= v4 ^ v12 + h[5] ^= v5 ^ v13 + h[6] ^= v6 ^ v14 + h[7] ^= v7 ^ v15 + } + c[0], c[1] = c0, c1 +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go new file mode 100644 index 000000000..da156a1ba --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !amd64 appengine gccgo + +package blake2b + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + hashBlocksGeneric(h, c, flag, blocks) +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_test.go b/vendor/golang.org/x/crypto/blake2b/blake2b_test.go new file mode 100644 index 000000000..a38fceb20 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_test.go @@ -0,0 +1,448 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import ( + "bytes" + "encoding/hex" + "fmt" + "hash" + "testing" +) + +func fromHex(s string) []byte { + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} + +func TestHashes(t *testing.T) { + defer func(sse4, avx, avx2 bool) { + useSSE4, useAVX, useAVX2 = sse4, useAVX, avx2 + }(useSSE4, useAVX, useAVX2) + + if useAVX2 { + t.Log("AVX2 version") + testHashes(t) + useAVX2 = false + } + if useAVX { + t.Log("AVX version") + testHashes(t) + useAVX = false + } + if useSSE4 { + t.Log("SSE4 version") + testHashes(t) + useSSE4 = false + } + t.Log("generic version") + testHashes(t) +} + +func testHashes(t *testing.T) { + key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f") + + input := make([]byte, 255) + for i := range input { + input[i] = byte(i) + } + + for i, expectedHex := range hashes { + h, err := New512(key) + if err != nil { + t.Fatalf("#%d: error from New512: %v", i, err) + } + + h.Write(input[:i]) + sum := h.Sum(nil) + + if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex { + t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex) + } + + h.Reset() + for j := 0; j < i; j++ { + h.Write(input[j : j+1]) + } + + sum = h.Sum(sum[:0]) + if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex { + t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex) + } + } +} + +func generateSequence(out []byte, seed uint32) { + a := 0xDEAD4BAD * seed // prime + b := uint32(1) + + for i := range out { // fill the buf + a, b = b, a+b + out[i] = byte(b >> 24) + } +} + +func computeMAC(msg []byte, hashSize int, key []byte) (sum []byte) { + var h hash.Hash + switch hashSize { + case Size: + h, _ = New512(key) + case Size384: + h, _ = New384(key) + case Size256: + h, _ = New256(key) + case 20: + h, _ = newDigest(20, key) + default: + panic("unexpected hashSize") + } + + h.Write(msg) + return h.Sum(sum) +} + +func computeHash(msg []byte, hashSize int) (sum []byte) { + switch hashSize { + case Size: + hash := Sum512(msg) + return hash[:] + case Size384: + hash := Sum384(msg) + return hash[:] + case Size256: + hash := Sum256(msg) + return hash[:] + case 20: + var hash [64]byte + checkSum(&hash, 20, msg) + return hash[:20] + default: + panic("unexpected hashSize") + } +} + +// Test function from RFC 7693. +func TestSelfTest(t *testing.T) { + hashLens := [4]int{20, 32, 48, 64} + msgLens := [6]int{0, 3, 128, 129, 255, 1024} + + msg := make([]byte, 1024) + key := make([]byte, 64) + + h, _ := New256(nil) + for _, hashSize := range hashLens { + for _, msgLength := range msgLens { + generateSequence(msg[:msgLength], uint32(msgLength)) // unkeyed hash + + md := computeHash(msg[:msgLength], hashSize) + h.Write(md) + + generateSequence(key[:], uint32(hashSize)) // keyed hash + md = computeMAC(msg[:msgLength], hashSize, key[:hashSize]) + h.Write(md) + } + } + + sum := h.Sum(nil) + expected := [32]byte{ + 0xc2, 0x3a, 0x78, 0x00, 0xd9, 0x81, 0x23, 0xbd, + 0x10, 0xf5, 0x06, 0xc6, 0x1e, 0x29, 0xda, 0x56, + 0x03, 0xd7, 0x63, 0xb8, 0xbb, 0xad, 0x2e, 0x73, + 0x7f, 0x5e, 0x76, 0x5a, 0x7b, 0xcc, 0xd4, 0x75, + } + if !bytes.Equal(sum, expected[:]) { + t.Fatalf("got %x, wanted %x", sum, expected) + } +} + +// Benchmarks + +func benchmarkSum(b *testing.B, size int) { + data := make([]byte, size) + b.SetBytes(int64(size)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Sum512(data) + } +} + +func benchmarkWrite(b *testing.B, size int) { + data := make([]byte, size) + h, _ := New512(nil) + b.SetBytes(int64(size)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Write(data) + } +} + +func BenchmarkWrite128(b *testing.B) { benchmarkWrite(b, 128) } +func BenchmarkWrite1K(b *testing.B) { benchmarkWrite(b, 1024) } + +func BenchmarkSum128(b *testing.B) { benchmarkSum(b, 128) } +func BenchmarkSum1K(b *testing.B) { benchmarkSum(b, 1024) } + +// These values were taken from https://blake2.net/blake2b-test.txt. +var hashes = []string{ + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568", + "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd", + "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965", + "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1", + "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac", + "098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb", + "6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f", + "7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52", + "380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9", + "60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637", + "4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd", + "f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b", + "962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563", + "43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355", + "dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6", + "6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e", + "a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93", + "f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1", + "95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670", + "04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9", + "ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c", + "9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd", + "4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152", + "64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9", + "5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f", + "7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b", + "f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764", + "86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d", + "10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55", + "b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b", + "c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e", + "eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7", + "86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991", + "5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347", + "ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82", + "7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42", + "940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327", + "2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760", + "d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252", + "b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55", + "4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1", + "258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee", + "79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa", + "8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7", + "c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071", + "b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4", + "7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf", + "a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d", + "41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8", + "14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487", + "d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c", + "e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2", + "feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa", + "462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33", + "d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d", + "e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e", + "f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2", + "30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4", + "f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2", + "0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a", + "08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564", + "d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f", + "dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9", + "bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa", + "65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022", + "939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c", + "c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc", + "987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f", + "ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b", + "49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866", + "da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d", + "d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8", + "2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4", + "e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3", + "dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e", + "d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745", + "b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545", + "6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063", + "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd", + "cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a", + "fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed", + "5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd", + "9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275", + "af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897", + "48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430", + "0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab", + "06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f", + "1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46", + "3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29", + "04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab", + "9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8", + "ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a", + "8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec", + "fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79", + "28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24", + "ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b", + "b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5", + "31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463", + "bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4", + "f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3", + "8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9", + "c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d", + "4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4", + "c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a", + "ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6", + "82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73", + "2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6", + "16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6", + "78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3", + "0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa", + "f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3", + "2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b", + "227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f", + "1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc", + "5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200", + "dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6", + "02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8", + "64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f", + "f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a", + "e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e", + "e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935", + "85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74", + "aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0", + "7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c", + "de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145", + "aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f", + "c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0", + "76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb", + "72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4", + "64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91", + "12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89", + "60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444", + "a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a", + "b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414", + "fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49", + "34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b", + "3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0", + "ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469", + "022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3", + "e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd", + "94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8", + "31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21", + "91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989", + "d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1", + "d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399", + "7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0", + "58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723", + "27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff", + "3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc", + "eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38", + "c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a", + "8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051", + "24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca", + "5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4", + "e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677", + "bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1", + "d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce", + "50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347", + "0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91", + "1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209", + "e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659", + "b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381", + "72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56", + "c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7", + "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f", + "6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972", + "3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe", + "c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e", + "8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be", + "28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8", + "2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc", + "66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8", + "f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0", + "8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc", + "3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979", + "06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29", + "c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d", + "4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108", + "898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45", + "ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4", + "3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267", + "95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d", + "227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb", + "5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813", + "7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc", + "062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29", + "f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc", + "ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16", + "c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1", + "15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c", + "89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7", + "e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a", + "8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa", + "da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e", + "f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc", + "11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5", + "b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a", + "ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3", + "29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc", + "3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d", + "3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff", + "07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb", + "b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4", + "7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc", + "1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902", + "106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e", + "0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08", + "521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816", + "1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406", + "5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4", + "b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d", + "bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d", + "65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900", + "ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06", + "e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01", + "3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0", + "fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94", + "951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02", + "8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492", + "16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2", + "c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c", + "72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb", + "c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077", + "c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727", + "f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd", + "348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c", + "5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0", + "2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403", + "b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391", + "64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8", + "0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605", + "f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9", + "3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d", + "d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe", + "cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe", + "98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1", + "771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3", + "c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb", + "8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b", + "1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef", + "af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253", + "29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec", + "a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a", + "0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473", + "b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837", + "74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a", + "3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1", + "58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d", + "9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9", + "b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537", + "1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7", + "4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2", + "695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338", + "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15", + "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9", + "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461", +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 87783717c..ef5b851e1 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -57,9 +57,10 @@ "revisionTime": "2015-12-24T06:54:52+02:00" }, { + "checksumSHA1": "XEBl9iQQvfXNlwCSzyAOCqAlYEA=", "path": "github.com/fatih/color", - "revision": "87d4004f2ab62d0d255e0a38f1680aa534549fe3", - "revisionTime": "2016-06-10T14:06:02+03:00" + "revision": "42c364ba490082e4815b5222728711b3440603eb", + "revisionTime": "2017-01-13T15:16:12Z" }, { "checksumSHA1": "3yco0089CSJ4qbyUccpbDC2+dPg=", @@ -150,9 +151,10 @@ "revisionTime": "2016-06-03T00:08:27+09:00" }, { + "checksumSHA1": "xZuhljnmBysJPta/lMyYmJdujCg=", "path": "github.com/mattn/go-isatty", - "revision": "56b76bdf51f7708750eac80fa38b952bb9f32639", - "revisionTime": "2015-12-11T09:06:21+09:00" + "revision": "30a891c33c7cde7b02a981314b4228ec99380cca", + "revisionTime": "2016-11-23T14:36:37Z" }, { "checksumSHA1": "4gphCNVXIjp5ytz3+S3SD3Dp948=",