')
+ .attr('id', this.containerId)
+ .html(html)
+
+ $(document.body).append(container)
+ return container
+ }
+
+ jasmine.Fixtures.prototype.addToContainer_ = function (html){
+ var container = $(document.body).find('#'+this.containerId).append(html)
+ if(!container.length){
+ this.createContainer_(html)
+ }
+ }
+
+ jasmine.Fixtures.prototype.getFixtureHtml_ = function (url) {
+ if (typeof this.fixturesCache_[url] === 'undefined') {
+ this.loadFixtureIntoCache_(url)
+ }
+ return this.fixturesCache_[url]
+ }
+
+ jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
+ var self = this
+ , url = this.makeFixtureUrl_(relativeUrl)
+ , request = $.ajax({
+ async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+ cache: false,
+ url: url,
+ success: function (data, status, $xhr) {
+ self.fixturesCache_[relativeUrl] = $xhr.responseText
+ },
+ error: function (jqXHR, status, errorThrown) {
+ throw new Error('Fixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')')
+ }
+ })
+ }
+
+ jasmine.Fixtures.prototype.makeFixtureUrl_ = function (relativeUrl){
+ return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+ }
+
+ jasmine.Fixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments)
+ }
+
+
+ jasmine.StyleFixtures = function () {
+ this.fixturesCache_ = {}
+ this.fixturesNodes_ = []
+ this.fixturesPath = 'spec/javascripts/fixtures'
+ }
+
+ jasmine.StyleFixtures.prototype.set = function (css) {
+ this.cleanUp()
+ this.createStyle_(css)
+ }
+
+ jasmine.StyleFixtures.prototype.appendSet = function (css) {
+ this.createStyle_(css)
+ }
+
+ jasmine.StyleFixtures.prototype.preload = function () {
+ this.read_.apply(this, arguments)
+ }
+
+ jasmine.StyleFixtures.prototype.load = function () {
+ this.cleanUp()
+ this.createStyle_(this.read_.apply(this, arguments))
+ }
+
+ jasmine.StyleFixtures.prototype.appendLoad = function () {
+ this.createStyle_(this.read_.apply(this, arguments))
+ }
+
+ jasmine.StyleFixtures.prototype.cleanUp = function () {
+ while(this.fixturesNodes_.length) {
+ this.fixturesNodes_.pop().remove()
+ }
+ }
+
+ jasmine.StyleFixtures.prototype.createStyle_ = function (html) {
+ var styleText = $('
').html(html).text()
+ , style = $('')
+
+ this.fixturesNodes_.push(style)
+ $('head').append(style)
+ }
+
+ jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
+ jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
+ jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
+ jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
+ jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
+ jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
+
+ jasmine.getJSONFixtures = function () {
+ return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
+ }
+
+ jasmine.JSONFixtures = function () {
+ this.fixturesCache_ = {}
+ this.fixturesPath = 'spec/javascripts/fixtures/json'
+ }
+
+ jasmine.JSONFixtures.prototype.load = function () {
+ this.read.apply(this, arguments)
+ return this.fixturesCache_
+ }
+
+ jasmine.JSONFixtures.prototype.read = function () {
+ var fixtureUrls = arguments
+
+ for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
+ this.getFixtureData_(fixtureUrls[urlIndex])
+ }
+
+ return this.fixturesCache_
+ }
+
+ jasmine.JSONFixtures.prototype.clearCache = function () {
+ this.fixturesCache_ = {}
+ }
+
+ jasmine.JSONFixtures.prototype.getFixtureData_ = function (url) {
+ if (!this.fixturesCache_[url]) this.loadFixtureIntoCache_(url)
+ return this.fixturesCache_[url]
+ }
+
+ jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function (relativeUrl) {
+ var self = this
+ , url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
+
+ $.ajax({
+ async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
+ cache: false,
+ dataType: 'json',
+ url: url,
+ success: function (data) {
+ self.fixturesCache_[relativeUrl] = data
+ },
+ error: function (jqXHR, status, errorThrown) {
+ throw new Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')')
+ }
+ })
+ }
+
+ jasmine.JSONFixtures.prototype.proxyCallTo_ = function (methodName, passedArguments) {
+ return this[methodName].apply(this, passedArguments)
+ }
+
+ jasmine.JQuery = function () {}
+
+ jasmine.JQuery.browserTagCaseIndependentHtml = function (html) {
+ return $('
').append(html).html()
+ }
+
+ jasmine.JQuery.elementToString = function (element) {
+ var domEl = $(element).get(0)
+
+ if (domEl === undefined || domEl.cloneNode)
+ return $('
').append($(element).clone()).html()
+ else
+ return element.toString()
+ }
+
+ jasmine.JQuery.matchersClass = {}
+
+ !function (namespace) {
+ var data = {
+ spiedEvents: {}
+ , handlers: []
+ }
+
+ namespace.events = {
+ spyOn: function (selector, eventName) {
+ var handler = function (e) {
+ data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments)
+ }
+
+ $(selector).on(eventName, handler)
+ data.handlers.push(handler)
+
+ return {
+ selector: selector,
+ eventName: eventName,
+ handler: handler,
+ reset: function (){
+ delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+ }
+ }
+ },
+
+ args: function (selector, eventName) {
+ var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+
+ if (!actualArgs) {
+ throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent."
+ }
+
+ return actualArgs
+ },
+
+ wasTriggered: function (selector, eventName) {
+ return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
+ },
+
+ wasTriggeredWith: function (selector, eventName, expectedArgs, env) {
+ var actualArgs = jasmine.JQuery.events.args(selector, eventName).slice(1)
+ if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') {
+ actualArgs = actualArgs[0]
+ }
+ return env.equals_(expectedArgs, actualArgs)
+ },
+
+ wasPrevented: function (selector, eventName) {
+ var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+ , e = args ? args[0] : undefined
+
+ return e && e.isDefaultPrevented()
+ },
+
+ wasStopped: function (selector, eventName) {
+ var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
+ , e = args ? args[0] : undefined
+ return e && e.isPropagationStopped()
+ },
+
+ cleanUp: function () {
+ data.spiedEvents = {}
+ data.handlers = []
+ }
+ }
+ }(jasmine.JQuery)
+
+ !function (){
+ var jQueryMatchers = {
+ toHaveClass: function (className) {
+ return this.actual.hasClass(className)
+ },
+
+ toHaveCss: function (css){
+ for (var prop in css){
+ var value = css[prop]
+ // see issue #147 on gh
+ ;if (value === 'auto' && this.actual.get(0).style[prop] === 'auto') continue
+ if (this.actual.css(prop) !== value) return false
+ }
+ return true
+ },
+
+ toBeVisible: function () {
+ return this.actual.is(':visible')
+ },
+
+ toBeHidden: function () {
+ return this.actual.is(':hidden')
+ },
+
+ toBeSelected: function () {
+ return this.actual.is(':selected')
+ },
+
+ toBeChecked: function () {
+ return this.actual.is(':checked')
+ },
+
+ toBeEmpty: function () {
+ return this.actual.is(':empty')
+ },
+
+ toExist: function () {
+ return this.actual.length
+ },
+
+ toHaveLength: function (length) {
+ return this.actual.length === length
+ },
+
+ toHaveAttr: function (attributeName, expectedAttributeValue) {
+ return hasProperty(this.actual.attr(attributeName), expectedAttributeValue)
+ },
+
+ toHaveProp: function (propertyName, expectedPropertyValue) {
+ return hasProperty(this.actual.prop(propertyName), expectedPropertyValue)
+ },
+
+ toHaveId: function (id) {
+ return this.actual.attr('id') == id
+ },
+
+ toHaveHtml: function (html) {
+ return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html)
+ },
+
+ toContainHtml: function (html){
+ var actualHtml = this.actual.html()
+ , expectedHtml = jasmine.JQuery.browserTagCaseIndependentHtml(html)
+
+ return (actualHtml.indexOf(expectedHtml) >= 0)
+ },
+
+ toHaveText: function (text) {
+ var trimmedText = $.trim(this.actual.text())
+
+ if (text && $.isFunction(text.test)) {
+ return text.test(trimmedText)
+ } else {
+ return trimmedText == text
+ }
+ },
+
+ toContainText: function (text) {
+ var trimmedText = $.trim(this.actual.text())
+
+ if (text && $.isFunction(text.test)) {
+ return text.test(trimmedText)
+ } else {
+ return trimmedText.indexOf(text) != -1
+ }
+ },
+
+ toHaveValue: function (value) {
+ return this.actual.val() === value
+ },
+
+ toHaveData: function (key, expectedValue) {
+ return hasProperty(this.actual.data(key), expectedValue)
+ },
+
+ toBe: function (selector) {
+ return this.actual.is(selector)
+ },
+
+ toContain: function (selector) {
+ return this.actual.find(selector).length
+ },
+
+ toBeMatchedBy: function (selector) {
+ return this.actual.filter(selector).length
+ },
+
+ toBeDisabled: function (selector){
+ return this.actual.is(':disabled')
+ },
+
+ toBeFocused: function (selector) {
+ return this.actual[0] === this.actual[0].ownerDocument.activeElement
+ },
+
+ toHandle: function (event) {
+ var events = $._data(this.actual.get(0), "events")
+
+ if(!events || !event || typeof event !== "string") {
+ return false
+ }
+
+ var namespaces = event.split(".")
+ , eventType = namespaces.shift()
+ , sortedNamespaces = namespaces.slice(0).sort()
+ , namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
+
+ if(events[eventType] && namespaces.length) {
+ for(var i = 0; i < events[eventType].length; i++) {
+ var namespace = events[eventType][i].namespace
+
+ if(namespaceRegExp.test(namespace)) {
+ return true
+ }
+ }
+ } else {
+ return events[eventType] && events[eventType].length > 0
+ }
+ },
+
+ toHandleWith: function (eventName, eventHandler) {
+ var normalizedEventName = eventName.split('.')[0]
+ , stack = $._data(this.actual.get(0), "events")[normalizedEventName]
+
+ for (var i = 0; i < stack.length; i++) {
+ if (stack[i].handler == eventHandler) return true
+ }
+
+ return false
+ }
+ }
+
+ var hasProperty = function (actualValue, expectedValue) {
+ if (expectedValue === undefined) return actualValue !== undefined
+
+ return actualValue == expectedValue
+ }
+
+ var bindMatcher = function (methodName) {
+ var builtInMatcher = jasmine.Matchers.prototype[methodName]
+
+ jasmine.JQuery.matchersClass[methodName] = function () {
+ if (this.actual
+ && (this.actual instanceof $
+ || jasmine.isDomNode(this.actual))) {
+ this.actual = $(this.actual)
+ var result = jQueryMatchers[methodName].apply(this, arguments)
+ , element
+
+ if (this.actual.get && (element = this.actual.get()[0]) && !$.isWindow(element) && element.tagName !== "HTML")
+ this.actual = jasmine.JQuery.elementToString(this.actual)
+
+ return result
+ }
+
+ if (builtInMatcher) {
+ return builtInMatcher.apply(this, arguments)
+ }
+
+ return false
+ }
+ }
+
+ for(var methodName in jQueryMatchers) {
+ bindMatcher(methodName)
+ }
+ }()
+
+ beforeEach(function () {
+ this.addMatchers(jasmine.JQuery.matchersClass)
+ this.addMatchers({
+ toHaveBeenTriggeredOn: function (selector) {
+ this.message = function () {
+ return [
+ "Expected event " + this.actual + " to have been triggered on " + selector,
+ "Expected event " + this.actual + " not to have been triggered on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasTriggered(selector, this.actual)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenTriggered: function (){
+ var eventName = this.actual.eventName
+ , selector = this.actual.selector
+
+ this.message = function () {
+ return [
+ "Expected event " + eventName + " to have been triggered on " + selector,
+ "Expected event " + eventName + " not to have been triggered on " + selector
+ ]
+ }
+
+ return jasmine.JQuery.events.wasTriggered(selector, eventName)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenTriggeredOnAndWith: function () {
+ var selector = arguments[0]
+ , expectedArgs = arguments[1]
+ , wasTriggered = jasmine.JQuery.events.wasTriggered(selector, this.actual)
+
+ this.message = function () {
+ if (wasTriggered) {
+ var actualArgs = jasmine.JQuery.events.args(selector, this.actual, expectedArgs)[1]
+ return [
+ "Expected event " + this.actual + " to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs),
+ "Expected event " + this.actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs)
+ ]
+ } else {
+ return [
+ "Expected event " + this.actual + " to have been triggered on " + selector,
+ "Expected event " + this.actual + " not to have been triggered on " + selector
+ ]
+ }
+ }
+
+ return wasTriggered && jasmine.JQuery.events.wasTriggeredWith(selector, this.actual, expectedArgs, this.env)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenPreventedOn: function (selector) {
+ this.message = function () {
+ return [
+ "Expected event " + this.actual + " to have been prevented on " + selector,
+ "Expected event " + this.actual + " not to have been prevented on " + selector
+ ]
+ }
+
+ return jasmine.JQuery.events.wasPrevented(selector, this.actual)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenPrevented: function () {
+ var eventName = this.actual.eventName
+ , selector = this.actual.selector
+ this.message = function () {
+ return [
+ "Expected event " + eventName + " to have been prevented on " + selector,
+ "Expected event " + eventName + " not to have been prevented on " + selector
+ ]
+ }
+
+ return jasmine.JQuery.events.wasPrevented(selector, eventName)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenStoppedOn: function (selector) {
+ this.message = function () {
+ return [
+ "Expected event " + this.actual + " to have been stopped on " + selector,
+ "Expected event " + this.actual + " not to have been stopped on " + selector
+ ]
+ }
+
+ return jasmine.JQuery.events.wasStopped(selector, this.actual)
+ }
+ })
+ this.addMatchers({
+ toHaveBeenStopped: function () {
+ var eventName = this.actual.eventName
+ , selector = this.actual.selector
+ this.message = function () {
+ return [
+ "Expected event " + eventName + " to have been stopped on " + selector,
+ "Expected event " + eventName + " not to have been stopped on " + selector
+ ]
+ }
+ return jasmine.JQuery.events.wasStopped(selector, eventName)
+ }
+ })
+ jasmine.getEnv().addEqualityTester(function (a, b) {
+ if(a instanceof jQuery && b instanceof jQuery) {
+ if(a.size() != b.size()) {
+ return jasmine.undefined
+ }
+ else if(a.is(b)) {
+ return true
+ }
+ }
+
+ return jasmine.undefined
+ })
+ })
+
+ afterEach(function () {
+ jasmine.getFixtures().cleanUp()
+ jasmine.getStyleFixtures().cleanUp()
+ jasmine.JQuery.events.cleanUp()
+ })
+}(window.jasmine, window.jQuery)
+
++function (jasmine, global) { "use strict";
+
+ global.readFixtures = function () {
+ return jasmine.getFixtures().proxyCallTo_('read', arguments)
+ }
+
+ global.preloadFixtures = function () {
+ jasmine.getFixtures().proxyCallTo_('preload', arguments)
+ }
+
+ global.loadFixtures = function () {
+ jasmine.getFixtures().proxyCallTo_('load', arguments)
+ }
+
+ global.appendLoadFixtures = function () {
+ jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
+ }
+
+ global.setFixtures = function (html) {
+ return jasmine.getFixtures().proxyCallTo_('set', arguments)
+ }
+
+ global.appendSetFixtures = function () {
+ jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
+ }
+
+ global.sandbox = function (attributes) {
+ return jasmine.getFixtures().sandbox(attributes)
+ }
+
+ global.spyOnEvent = function (selector, eventName) {
+ return jasmine.JQuery.events.spyOn(selector, eventName)
+ }
+
+ global.preloadStyleFixtures = function () {
+ jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
+ }
+
+ global.loadStyleFixtures = function () {
+ jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
+ }
+
+ global.appendLoadStyleFixtures = function () {
+ jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
+ }
+
+ global.setStyleFixtures = function (html) {
+ jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
+ }
+
+ global.appendSetStyleFixtures = function (html) {
+ jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
+ }
+
+ global.loadJSONFixtures = function () {
+ return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
+ }
+
+ global.getJSONFixture = function (url) {
+ return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
+ }
+}(jasmine, window);
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/helpers/jasmine-sinon.js b/wms/contract-repair/semantic/test/helpers/jasmine-sinon.js
new file mode 100644
index 00000000..c9356532
--- /dev/null
+++ b/wms/contract-repair/semantic/test/helpers/jasmine-sinon.js
@@ -0,0 +1,58 @@
+/* global jasmine */
+
+'use strict';
+
+(function(jasmine, beforeEach) {
+
+ var sinon = (typeof require === 'function' && typeof module === 'object') ? require('sinon') : window.sinon,
+ spyMatchers = 'called calledOnce calledTwice calledThrice calledBefore calledAfter calledOn alwaysCalledOn calledWith alwaysCalledWith calledWithExactly alwaysCalledWithExactly calledWithMatch alwaysCalledWithMatch'.split(' '),
+ i = spyMatchers.length,
+ spyMatcherHash = {},
+ unusualMatchers = {
+ "returned": "toHaveReturned",
+ "alwaysReturned": "toHaveAlwaysReturned",
+ "threw": "toHaveThrown",
+ "alwaysThrew": "toHaveAlwaysThrown"
+ },
+
+ createCustomMatcher = function(arg) {
+ return sinon.match(function (val) {
+ return jasmine.getEnv().equals_(val, arg);
+ });
+ },
+
+ getMatcherFunction = function(sinonName, matcherName) {
+ var original = jasmine.Matchers.prototype[matcherName];
+ return function () {
+ if (jasmine.isSpy(this.actual) && original) {
+ return original.apply(this, arguments);
+ }
+ var sinonProperty = this.actual[sinonName];
+ var args = Array.prototype.slice.call(arguments);
+
+ for (var i = 0; i < args.length; i++) {
+ if (args[i] && (typeof args[i].jasmineMatches === 'function' || args[i] instanceof jasmine.Matchers.ObjectContaining)) {
+ args[i] = createCustomMatcher(args[i]);
+ }
+ }
+
+ return (typeof sinonProperty === 'function') ? sinonProperty.apply(this.actual, args) : sinonProperty;
+ };
+ };
+
+ while(i--) {
+ var sinonName = spyMatchers[i],
+ matcherName = "toHaveBeen" + sinonName.charAt(0).toUpperCase() + sinonName.slice(1);
+
+ spyMatcherHash[matcherName] = getMatcherFunction(sinonName, matcherName);
+ }
+
+ for (var j in unusualMatchers) {
+ spyMatcherHash[unusualMatchers[j]] = getMatcherFunction(j, unusualMatchers[j]);
+ }
+
+ beforeEach(function() {
+ this.addMatchers(spyMatcherHash);
+ });
+
+})(jasmine, beforeEach);
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/helpers/jquery-events.js b/wms/contract-repair/semantic/test/helpers/jquery-events.js
new file mode 100644
index 00000000..d956e567
--- /dev/null
+++ b/wms/contract-repair/semantic/test/helpers/jquery-events.js
@@ -0,0 +1,28 @@
+(function($) {
+ $.events = function(selector, root) {
+ var s = [];
+ $(selector || '*', root).addBack().each(function() {
+ // the following line is the only change
+ var e = $._data(this, 'events');
+ if(!e) return;
+ s.push(this.tagName);
+ if(this.id) s.push('#', this.id);
+ if(this.className) s.push('.', this.className.replace(/ +/g, '.'));
+ for(var p in e) {
+ var r = e[p],
+ h = r.length - r.delegateCount;
+ if(h)
+ s.push('\n', h, ' ', p, ' handler', h > 1 ? 's' : '');
+ if(r.delegateCount) {
+ for(var q = 0; q < r.length; q++)
+ if(r[q].selector) s.push('\n', p, ' for ', r[q].selector);
+ }
+ }
+ s.push('\n\n');
+ });
+ return s.join('');
+ }
+ $.fn.events = function(selector) {
+ return $.events(selector, this);
+ }
+})(jQuery);
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/helpers/sinon.js b/wms/contract-repair/semantic/test/helpers/sinon.js
new file mode 100644
index 00000000..4112185d
--- /dev/null
+++ b/wms/contract-repair/semantic/test/helpers/sinon.js
@@ -0,0 +1,4819 @@
+/**
+ * Sinon.JS 1.9.1, 2014/04/03
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
+ *
+ * (The BSD License)
+ *
+ * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Christian Johansen nor the names of his contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+this.sinon = (function () {
+var samsam, formatio;
+function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else { formatio = fn(samsam); } }
+define.amd = true;
+((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
+ (typeof module === "object" &&
+ function (m) { module.exports = m(); }) || // Node
+ function (m) { this.samsam = m(); } // Browser globals
+)(function () {
+ var o = Object.prototype;
+ var div = typeof document !== "undefined" && document.createElement("div");
+
+ function isNaN(value) {
+ // Unlike global isNaN, this avoids type coercion
+ // typeof check avoids IE host object issues, hat tip to
+ // lodash
+ var val = value; // JsLint thinks value !== value is "weird"
+ return typeof value === "number" && value !== val;
+ }
+
+ function getClass(value) {
+ // Returns the internal [[Class]] by calling Object.prototype.toString
+ // with the provided value as this. Return value is a string, naming the
+ // internal class, e.g. "Array"
+ return o.toString.call(value).split(/[ \]]/)[1];
+ }
+
+ /**
+ * @name samsam.isArguments
+ * @param Object object
+ *
+ * Returns ``true`` if ``object`` is an ``arguments`` object,
+ * ``false`` otherwise.
+ */
+ function isArguments(object) {
+ if (typeof object !== "object" || typeof object.length !== "number" ||
+ getClass(object) === "Array") {
+ return false;
+ }
+ if (typeof object.callee == "function") { return true; }
+ try {
+ object[object.length] = 6;
+ delete object[object.length];
+ } catch (e) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @name samsam.isElement
+ * @param Object object
+ *
+ * Returns ``true`` if ``object`` is a DOM element node. Unlike
+ * Underscore.js/lodash, this function will return ``false`` if ``object``
+ * is an *element-like* object, i.e. a regular object with a ``nodeType``
+ * property that holds the value ``1``.
+ */
+ function isElement(object) {
+ if (!object || object.nodeType !== 1 || !div) { return false; }
+ try {
+ object.appendChild(div);
+ object.removeChild(div);
+ } catch (e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @name samsam.keys
+ * @param Object object
+ *
+ * Return an array of own property names.
+ */
+ function keys(object) {
+ var ks = [], prop;
+ for (prop in object) {
+ if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
+ }
+ return ks;
+ }
+
+ /**
+ * @name samsam.isDate
+ * @param Object value
+ *
+ * Returns true if the object is a ``Date``, or *date-like*. Duck typing
+ * of date objects work by checking that the object has a ``getTime``
+ * function whose return value equals the return value from the object's
+ * ``valueOf``.
+ */
+ function isDate(value) {
+ return typeof value.getTime == "function" &&
+ value.getTime() == value.valueOf();
+ }
+
+ /**
+ * @name samsam.isNegZero
+ * @param Object value
+ *
+ * Returns ``true`` if ``value`` is ``-0``.
+ */
+ function isNegZero(value) {
+ return value === 0 && 1 / value === -Infinity;
+ }
+
+ /**
+ * @name samsam.equal
+ * @param Object obj1
+ * @param Object obj2
+ *
+ * Returns ``true`` if two objects are strictly equal. Compared to
+ * ``===`` there are two exceptions:
+ *
+ * - NaN is considered equal to NaN
+ * - -0 and +0 are not considered equal
+ */
+ function identical(obj1, obj2) {
+ if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
+ return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
+ }
+ }
+
+
+ /**
+ * @name samsam.deepEqual
+ * @param Object obj1
+ * @param Object obj2
+ *
+ * Deep equal comparison. Two values are "deep equal" if:
+ *
+ * - They are equal, according to samsam.identical
+ * - They are both date objects representing the same time
+ * - They are both arrays containing elements that are all deepEqual
+ * - They are objects with the same set of properties, and each property
+ * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
+ *
+ * Supports cyclic objects.
+ */
+ function deepEqualCyclic(obj1, obj2) {
+
+ // used for cyclic comparison
+ // contain already visited objects
+ var objects1 = [],
+ objects2 = [],
+ // contain paths (position in the object structure)
+ // of the already visited objects
+ // indexes same as in objects arrays
+ paths1 = [],
+ paths2 = [],
+ // contains combinations of already compared objects
+ // in the manner: { "$1['ref']$2['ref']": true }
+ compared = {};
+
+ /**
+ * used to check, if the value of a property is an object
+ * (cyclic logic is only needed for objects)
+ * only needed for cyclic logic
+ */
+ function isObject(value) {
+
+ if (typeof value === 'object' && value !== null &&
+ !(value instanceof Boolean) &&
+ !(value instanceof Date) &&
+ !(value instanceof Number) &&
+ !(value instanceof RegExp) &&
+ !(value instanceof String)) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * returns the index of the given object in the
+ * given objects array, -1 if not contained
+ * only needed for cyclic logic
+ */
+ function getIndex(objects, obj) {
+
+ var i;
+ for (i = 0; i < objects.length; i++) {
+ if (objects[i] === obj) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ // does the recursion for the deep equal check
+ return (function deepEqual(obj1, obj2, path1, path2) {
+ var type1 = typeof obj1;
+ var type2 = typeof obj2;
+
+ // == null also matches undefined
+ if (obj1 === obj2 ||
+ isNaN(obj1) || isNaN(obj2) ||
+ obj1 == null || obj2 == null ||
+ type1 !== "object" || type2 !== "object") {
+
+ return identical(obj1, obj2);
+ }
+
+ // Elements are only equal if identical(expected, actual)
+ if (isElement(obj1) || isElement(obj2)) { return false; }
+
+ var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
+ if (isDate1 || isDate2) {
+ if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
+ return false;
+ }
+ }
+
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
+ if (obj1.toString() !== obj2.toString()) { return false; }
+ }
+
+ var class1 = getClass(obj1);
+ var class2 = getClass(obj2);
+ var keys1 = keys(obj1);
+ var keys2 = keys(obj2);
+
+ if (isArguments(obj1) || isArguments(obj2)) {
+ if (obj1.length !== obj2.length) { return false; }
+ } else {
+ if (type1 !== type2 || class1 !== class2 ||
+ keys1.length !== keys2.length) {
+ return false;
+ }
+ }
+
+ var key, i, l,
+ // following vars are used for the cyclic logic
+ value1, value2,
+ isObject1, isObject2,
+ index1, index2,
+ newPath1, newPath2;
+
+ for (i = 0, l = keys1.length; i < l; i++) {
+ key = keys1[i];
+ if (!o.hasOwnProperty.call(obj2, key)) {
+ return false;
+ }
+
+ // Start of the cyclic logic
+
+ value1 = obj1[key];
+ value2 = obj2[key];
+
+ isObject1 = isObject(value1);
+ isObject2 = isObject(value2);
+
+ // determine, if the objects were already visited
+ // (it's faster to check for isObject first, than to
+ // get -1 from getIndex for non objects)
+ index1 = isObject1 ? getIndex(objects1, value1) : -1;
+ index2 = isObject2 ? getIndex(objects2, value2) : -1;
+
+ // determine the new paths of the objects
+ // - for non cyclic objects the current path will be extended
+ // by current property name
+ // - for cyclic objects the stored path is taken
+ newPath1 = index1 !== -1
+ ? paths1[index1]
+ : path1 + '[' + JSON.stringify(key) + ']';
+ newPath2 = index2 !== -1
+ ? paths2[index2]
+ : path2 + '[' + JSON.stringify(key) + ']';
+
+ // stop recursion if current objects are already compared
+ if (compared[newPath1 + newPath2]) {
+ return true;
+ }
+
+ // remember the current objects and their paths
+ if (index1 === -1 && isObject1) {
+ objects1.push(value1);
+ paths1.push(newPath1);
+ }
+ if (index2 === -1 && isObject2) {
+ objects2.push(value2);
+ paths2.push(newPath2);
+ }
+
+ // remember that the current objects are already compared
+ if (isObject1 && isObject2) {
+ compared[newPath1 + newPath2] = true;
+ }
+
+ // End of cyclic logic
+
+ // neither value1 nor value2 is a cycle
+ // continue with next level
+ if (!deepEqual(value1, value2, newPath1, newPath2)) {
+ return false;
+ }
+ }
+
+ return true;
+
+ }(obj1, obj2, '$1', '$2'));
+ }
+
+ var match;
+
+ function arrayContains(array, subset) {
+ if (subset.length === 0) { return true; }
+ var i, l, j, k;
+ for (i = 0, l = array.length; i < l; ++i) {
+ if (match(array[i], subset[0])) {
+ for (j = 0, k = subset.length; j < k; ++j) {
+ if (!match(array[i + j], subset[j])) { return false; }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @name samsam.match
+ * @param Object object
+ * @param Object matcher
+ *
+ * Compare arbitrary value ``object`` with matcher.
+ */
+ match = function match(object, matcher) {
+ if (matcher && typeof matcher.test === "function") {
+ return matcher.test(object);
+ }
+
+ if (typeof matcher === "function") {
+ return matcher(object) === true;
+ }
+
+ if (typeof matcher === "string") {
+ matcher = matcher.toLowerCase();
+ var notNull = typeof object === "string" || !!object;
+ return notNull &&
+ (String(object)).toLowerCase().indexOf(matcher) >= 0;
+ }
+
+ if (typeof matcher === "number") {
+ return matcher === object;
+ }
+
+ if (typeof matcher === "boolean") {
+ return matcher === object;
+ }
+
+ if (getClass(object) === "Array" && getClass(matcher) === "Array") {
+ return arrayContains(object, matcher);
+ }
+
+ if (matcher && typeof matcher === "object") {
+ var prop;
+ for (prop in matcher) {
+ if (!match(object[prop], matcher[prop])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ throw new Error("Matcher was not a string, a number, a " +
+ "function, a boolean or an object");
+ };
+
+ return {
+ isArguments: isArguments,
+ isElement: isElement,
+ isDate: isDate,
+ isNegZero: isNegZero,
+ identical: identical,
+ deepEqual: deepEqualCyclic,
+ match: match,
+ keys: keys
+ };
+});
+((typeof define === "function" && define.amd && function (m) {
+ define("formatio", ["samsam"], m);
+}) || (typeof module === "object" && function (m) {
+ module.exports = m(require("samsam"));
+}) || function (m) { this.formatio = m(this.samsam); }
+)(function (samsam) {
+
+ var formatio = {
+ excludeConstructors: ["Object", /^.$/],
+ quoteStrings: true
+ };
+
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ var specialObjects = [];
+ if (typeof global !== "undefined") {
+ specialObjects.push({ object: global, value: "[object global]" });
+ }
+ if (typeof document !== "undefined") {
+ specialObjects.push({
+ object: document,
+ value: "[object HTMLDocument]"
+ });
+ }
+ if (typeof window !== "undefined") {
+ specialObjects.push({ object: window, value: "[object Window]" });
+ }
+
+ function functionName(func) {
+ if (!func) { return ""; }
+ if (func.displayName) { return func.displayName; }
+ if (func.name) { return func.name; }
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
+ return (matches && matches[1]) || "";
+ }
+
+ function constructorName(f, object) {
+ var name = functionName(object && object.constructor);
+ var excludes = f.excludeConstructors ||
+ formatio.excludeConstructors || [];
+
+ var i, l;
+ for (i = 0, l = excludes.length; i < l; ++i) {
+ if (typeof excludes[i] === "string" && excludes[i] === name) {
+ return "";
+ } else if (excludes[i].test && excludes[i].test(name)) {
+ return "";
+ }
+ }
+
+ return name;
+ }
+
+ function isCircular(object, objects) {
+ if (typeof object !== "object") { return false; }
+ var i, l;
+ for (i = 0, l = objects.length; i < l; ++i) {
+ if (objects[i] === object) { return true; }
+ }
+ return false;
+ }
+
+ function ascii(f, object, processed, indent) {
+ if (typeof object === "string") {
+ var qs = f.quoteStrings;
+ var quote = typeof qs !== "boolean" || qs;
+ return processed || quote ? '"' + object + '"' : object;
+ }
+
+ if (typeof object === "function" && !(object instanceof RegExp)) {
+ return ascii.func(object);
+ }
+
+ processed = processed || [];
+
+ if (isCircular(object, processed)) { return "[Circular]"; }
+
+ if (Object.prototype.toString.call(object) === "[object Array]") {
+ return ascii.array.call(f, object, processed);
+ }
+
+ if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
+ if (samsam.isElement(object)) { return ascii.element(object); }
+
+ if (typeof object.toString === "function" &&
+ object.toString !== Object.prototype.toString) {
+ return object.toString();
+ }
+
+ var i, l;
+ for (i = 0, l = specialObjects.length; i < l; i++) {
+ if (object === specialObjects[i].object) {
+ return specialObjects[i].value;
+ }
+ }
+
+ return ascii.object.call(f, object, processed, indent);
+ }
+
+ ascii.func = function (func) {
+ return "function " + functionName(func) + "() {}";
+ };
+
+ ascii.array = function (array, processed) {
+ processed = processed || [];
+ processed.push(array);
+ var i, l, pieces = [];
+ for (i = 0, l = array.length; i < l; ++i) {
+ pieces.push(ascii(this, array[i], processed));
+ }
+ return "[" + pieces.join(", ") + "]";
+ };
+
+ ascii.object = function (object, processed, indent) {
+ processed = processed || [];
+ processed.push(object);
+ indent = indent || 0;
+ var pieces = [], properties = samsam.keys(object).sort();
+ var length = 3;
+ var prop, str, obj, i, l;
+
+ for (i = 0, l = properties.length; i < l; ++i) {
+ prop = properties[i];
+ obj = object[prop];
+
+ if (isCircular(obj, processed)) {
+ str = "[Circular]";
+ } else {
+ str = ascii(this, obj, processed, indent + 2);
+ }
+
+ str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+ length += str.length;
+ pieces.push(str);
+ }
+
+ var cons = constructorName(this, object);
+ var prefix = cons ? "[" + cons + "] " : "";
+ var is = "";
+ for (i = 0, l = indent; i < l; ++i) { is += " "; }
+
+ if (length + indent > 80) {
+ return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
+ is + "}";
+ }
+ return prefix + "{ " + pieces.join(", ") + " }";
+ };
+
+ ascii.element = function (element) {
+ var tagName = element.tagName.toLowerCase();
+ var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
+
+ for (i = 0, l = attrs.length; i < l; ++i) {
+ attr = attrs.item(i);
+ attrName = attr.nodeName.toLowerCase().replace("html:", "");
+ val = attr.nodeValue;
+ if (attrName !== "contenteditable" || val !== "inherit") {
+ if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
+ }
+ }
+
+ var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+ var content = element.innerHTML;
+
+ if (content.length > 20) {
+ content = content.substr(0, 20) + "[...]";
+ }
+
+ var res = formatted + pairs.join(" ") + ">" + content +
+ "" + tagName + ">";
+
+ return res.replace(/ contentEditable="inherit"/, "");
+ };
+
+ function Formatio(options) {
+ for (var opt in options) {
+ this[opt] = options[opt];
+ }
+ }
+
+ Formatio.prototype = {
+ functionName: functionName,
+
+ configure: function (options) {
+ return new Formatio(options);
+ },
+
+ constructorName: function (object) {
+ return constructorName(this, object);
+ },
+
+ ascii: function (object, processed, indent) {
+ return ascii(this, object, processed, indent);
+ }
+ };
+
+ return Formatio.prototype;
+});
+/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
+/*global module, require, __dirname, document*/
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+var sinon = (function (formatio) {
+ var div = typeof document != "undefined" && document.createElement("div");
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ function isDOMNode(obj) {
+ var success = false;
+
+ try {
+ obj.appendChild(div);
+ success = div.parentNode == obj;
+ } catch (e) {
+ return false;
+ } finally {
+ try {
+ obj.removeChild(div);
+ } catch (e) {
+ // Remove failed, not much we can do about that
+ }
+ }
+
+ return success;
+ }
+
+ function isElement(obj) {
+ return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+ }
+
+ function isFunction(obj) {
+ return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
+ }
+
+ function isReallyNaN(val) {
+ return typeof val === 'number' && isNaN(val);
+ }
+
+ function mirrorProperties(target, source) {
+ for (var prop in source) {
+ if (!hasOwn.call(target, prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+
+ function isRestorable (obj) {
+ return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
+ }
+
+ var sinon = {
+ wrapMethod: function wrapMethod(object, property, method) {
+ if (!object) {
+ throw new TypeError("Should wrap property of object");
+ }
+
+ if (typeof method != "function") {
+ throw new TypeError("Method wrapper should be function");
+ }
+
+ var wrappedMethod = object[property],
+ error;
+
+ if (!isFunction(wrappedMethod)) {
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ property + " as function");
+ }
+
+ if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+ error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+ }
+
+ if (wrappedMethod.calledBefore) {
+ var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
+ error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
+ }
+
+ if (error) {
+ if (wrappedMethod._stack) {
+ error.stack += '\n--------------\n' + wrappedMethod._stack;
+ }
+ throw error;
+ }
+
+ // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
+ // when using hasOwn.call on objects from other frames.
+ var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
+ object[property] = method;
+ method.displayName = property;
+ // Set up a stack trace which can be used later to find what line of
+ // code the original method was created on.
+ method._stack = (new Error('Stack Trace for original')).stack;
+
+ method.restore = function () {
+ // For prototype properties try to reset by delete first.
+ // If this fails (ex: localStorage on mobile safari) then force a reset
+ // via direct assignment.
+ if (!owned) {
+ delete object[property];
+ }
+ if (object[property] === method) {
+ object[property] = wrappedMethod;
+ }
+ };
+
+ method.restore.sinon = true;
+ mirrorProperties(method, wrappedMethod);
+
+ return method;
+ },
+
+ extend: function extend(target) {
+ for (var i = 1, l = arguments.length; i < l; i += 1) {
+ for (var prop in arguments[i]) {
+ if (arguments[i].hasOwnProperty(prop)) {
+ target[prop] = arguments[i][prop];
+ }
+
+ // DONT ENUM bug, only care about toString
+ if (arguments[i].hasOwnProperty("toString") &&
+ arguments[i].toString != target.toString) {
+ target.toString = arguments[i].toString;
+ }
+ }
+ }
+
+ return target;
+ },
+
+ create: function create(proto) {
+ var F = function () {};
+ F.prototype = proto;
+ return new F();
+ },
+
+ deepEqual: function deepEqual(a, b) {
+ if (sinon.match && sinon.match.isMatcher(a)) {
+ return a.test(b);
+ }
+
+ if (typeof a != 'object' || typeof b != 'object') {
+ if (isReallyNaN(a) && isReallyNaN(b)) {
+ return true;
+ } else {
+ return a === b;
+ }
+ }
+
+ if (isElement(a) || isElement(b)) {
+ return a === b;
+ }
+
+ if (a === b) {
+ return true;
+ }
+
+ if ((a === null && b !== null) || (a !== null && b === null)) {
+ return false;
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return (a.source === b.source) && (a.global === b.global) &&
+ (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
+ }
+
+ var aString = Object.prototype.toString.call(a);
+ if (aString != Object.prototype.toString.call(b)) {
+ return false;
+ }
+
+ if (aString == "[object Date]") {
+ return a.valueOf() === b.valueOf();
+ }
+
+ var prop, aLength = 0, bLength = 0;
+
+ if (aString == "[object Array]" && a.length !== b.length) {
+ return false;
+ }
+
+ for (prop in a) {
+ aLength += 1;
+
+ if (!deepEqual(a[prop], b[prop])) {
+ return false;
+ }
+ }
+
+ for (prop in b) {
+ bLength += 1;
+ }
+
+ return aLength == bLength;
+ },
+
+ functionName: function functionName(func) {
+ var name = func.displayName || func.name;
+
+ // Use function decomposition as a last resort to get function
+ // name. Does not rely on function decomposition to work - if it
+ // doesn't debugging will be slightly less informative
+ // (i.e. toString will say 'spy' rather than 'myFunc').
+ if (!name) {
+ var matches = func.toString().match(/function ([^\s\(]+)/);
+ name = matches && matches[1];
+ }
+
+ return name;
+ },
+
+ functionToString: function toString() {
+ if (this.getCall && this.callCount) {
+ var thisValue, prop, i = this.callCount;
+
+ while (i--) {
+ thisValue = this.getCall(i).thisValue;
+
+ for (prop in thisValue) {
+ if (thisValue[prop] === this) {
+ return prop;
+ }
+ }
+ }
+ }
+
+ return this.displayName || "sinon fake";
+ },
+
+ getConfig: function (custom) {
+ var config = {};
+ custom = custom || {};
+ var defaults = sinon.defaultConfig;
+
+ for (var prop in defaults) {
+ if (defaults.hasOwnProperty(prop)) {
+ config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
+ }
+ }
+
+ return config;
+ },
+
+ format: function (val) {
+ return "" + val;
+ },
+
+ defaultConfig: {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ },
+
+ timesInWords: function timesInWords(count) {
+ return count == 1 && "once" ||
+ count == 2 && "twice" ||
+ count == 3 && "thrice" ||
+ (count || 0) + " times";
+ },
+
+ calledInOrder: function (spies) {
+ for (var i = 1, l = spies.length; i < l; i++) {
+ if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ orderByFirstCall: function (spies) {
+ return spies.sort(function (a, b) {
+ // uuid, won't ever be equal
+ var aCall = a.getCall(0);
+ var bCall = b.getCall(0);
+ var aId = aCall && aCall.callId || -1;
+ var bId = bCall && bCall.callId || -1;
+
+ return aId < bId ? -1 : 1;
+ });
+ },
+
+ log: function () {},
+
+ logError: function (label, err) {
+ var msg = label + " threw exception: ";
+ sinon.log(msg + "[" + err.name + "] " + err.message);
+ if (err.stack) { sinon.log(err.stack); }
+
+ setTimeout(function () {
+ err.message = msg + err.message;
+ throw err;
+ }, 0);
+ },
+
+ typeOf: function (value) {
+ if (value === null) {
+ return "null";
+ }
+ else if (value === undefined) {
+ return "undefined";
+ }
+ var string = Object.prototype.toString.call(value);
+ return string.substring(8, string.length - 1).toLowerCase();
+ },
+
+ createStubInstance: function (constructor) {
+ if (typeof constructor !== "function") {
+ throw new TypeError("The constructor should be a function.");
+ }
+ return sinon.stub(sinon.create(constructor.prototype));
+ },
+
+ restore: function (object) {
+ if (object !== null && typeof object === "object") {
+ for (var prop in object) {
+ if (isRestorable(object[prop])) {
+ object[prop].restore();
+ }
+ }
+ }
+ else if (isRestorable(object)) {
+ object.restore();
+ }
+ }
+ };
+
+ var isNode = typeof module !== "undefined" && module.exports;
+ var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
+
+ if (isAMD) {
+ define(function(){
+ return sinon;
+ });
+ } else if (isNode) {
+ try {
+ formatio = require("formatio");
+ } catch (e) {}
+ module.exports = sinon;
+ module.exports.spy = require("./sinon/spy");
+ module.exports.spyCall = require("./sinon/call");
+ module.exports.behavior = require("./sinon/behavior");
+ module.exports.stub = require("./sinon/stub");
+ module.exports.mock = require("./sinon/mock");
+ module.exports.collection = require("./sinon/collection");
+ module.exports.assert = require("./sinon/assert");
+ module.exports.sandbox = require("./sinon/sandbox");
+ module.exports.test = require("./sinon/test");
+ module.exports.testCase = require("./sinon/test_case");
+ module.exports.assert = require("./sinon/assert");
+ module.exports.match = require("./sinon/match");
+ }
+
+ if (formatio) {
+ var formatter = formatio.configure({ quoteStrings: false });
+ sinon.format = function () {
+ return formatter.ascii.apply(formatter, arguments);
+ };
+ } else if (isNode) {
+ try {
+ var util = require("util");
+ sinon.format = function (value) {
+ return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
+ };
+ } catch (e) {
+ /* Node, but no util module - would be very old, but better safe than
+ sorry */
+ }
+ }
+
+ return sinon;
+}(typeof formatio == "object" && formatio));
+
+/* @depend ../sinon.js */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Match functions
+ *
+ * @author Maximilian Antoni (mail@maxantoni.de)
+ * @license BSD
+ *
+ * Copyright (c) 2012 Maximilian Antoni
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function assertType(value, type, name) {
+ var actual = sinon.typeOf(value);
+ if (actual !== type) {
+ throw new TypeError("Expected type of " + name + " to be " +
+ type + ", but was " + actual);
+ }
+ }
+
+ var matcher = {
+ toString: function () {
+ return this.message;
+ }
+ };
+
+ function isMatcher(object) {
+ return matcher.isPrototypeOf(object);
+ }
+
+ function matchObject(expectation, actual) {
+ if (actual === null || actual === undefined) {
+ return false;
+ }
+ for (var key in expectation) {
+ if (expectation.hasOwnProperty(key)) {
+ var exp = expectation[key];
+ var act = actual[key];
+ if (match.isMatcher(exp)) {
+ if (!exp.test(act)) {
+ return false;
+ }
+ } else if (sinon.typeOf(exp) === "object") {
+ if (!matchObject(exp, act)) {
+ return false;
+ }
+ } else if (!sinon.deepEqual(exp, act)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ matcher.or = function (m2) {
+ if (!arguments.length) {
+ throw new TypeError("Matcher expected");
+ } else if (!isMatcher(m2)) {
+ m2 = match(m2);
+ }
+ var m1 = this;
+ var or = sinon.create(matcher);
+ or.test = function (actual) {
+ return m1.test(actual) || m2.test(actual);
+ };
+ or.message = m1.message + ".or(" + m2.message + ")";
+ return or;
+ };
+
+ matcher.and = function (m2) {
+ if (!arguments.length) {
+ throw new TypeError("Matcher expected");
+ } else if (!isMatcher(m2)) {
+ m2 = match(m2);
+ }
+ var m1 = this;
+ var and = sinon.create(matcher);
+ and.test = function (actual) {
+ return m1.test(actual) && m2.test(actual);
+ };
+ and.message = m1.message + ".and(" + m2.message + ")";
+ return and;
+ };
+
+ var match = function (expectation, message) {
+ var m = sinon.create(matcher);
+ var type = sinon.typeOf(expectation);
+ switch (type) {
+ case "object":
+ if (typeof expectation.test === "function") {
+ m.test = function (actual) {
+ return expectation.test(actual) === true;
+ };
+ m.message = "match(" + sinon.functionName(expectation.test) + ")";
+ return m;
+ }
+ var str = [];
+ for (var key in expectation) {
+ if (expectation.hasOwnProperty(key)) {
+ str.push(key + ": " + expectation[key]);
+ }
+ }
+ m.test = function (actual) {
+ return matchObject(expectation, actual);
+ };
+ m.message = "match(" + str.join(", ") + ")";
+ break;
+ case "number":
+ m.test = function (actual) {
+ return expectation == actual;
+ };
+ break;
+ case "string":
+ m.test = function (actual) {
+ if (typeof actual !== "string") {
+ return false;
+ }
+ return actual.indexOf(expectation) !== -1;
+ };
+ m.message = "match(\"" + expectation + "\")";
+ break;
+ case "regexp":
+ m.test = function (actual) {
+ if (typeof actual !== "string") {
+ return false;
+ }
+ return expectation.test(actual);
+ };
+ break;
+ case "function":
+ m.test = expectation;
+ if (message) {
+ m.message = message;
+ } else {
+ m.message = "match(" + sinon.functionName(expectation) + ")";
+ }
+ break;
+ default:
+ m.test = function (actual) {
+ return sinon.deepEqual(expectation, actual);
+ };
+ }
+ if (!m.message) {
+ m.message = "match(" + expectation + ")";
+ }
+ return m;
+ };
+
+ match.isMatcher = isMatcher;
+
+ match.any = match(function () {
+ return true;
+ }, "any");
+
+ match.defined = match(function (actual) {
+ return actual !== null && actual !== undefined;
+ }, "defined");
+
+ match.truthy = match(function (actual) {
+ return !!actual;
+ }, "truthy");
+
+ match.falsy = match(function (actual) {
+ return !actual;
+ }, "falsy");
+
+ match.same = function (expectation) {
+ return match(function (actual) {
+ return expectation === actual;
+ }, "same(" + expectation + ")");
+ };
+
+ match.typeOf = function (type) {
+ assertType(type, "string", "type");
+ return match(function (actual) {
+ return sinon.typeOf(actual) === type;
+ }, "typeOf(\"" + type + "\")");
+ };
+
+ match.instanceOf = function (type) {
+ assertType(type, "function", "type");
+ return match(function (actual) {
+ return actual instanceof type;
+ }, "instanceOf(" + sinon.functionName(type) + ")");
+ };
+
+ function createPropertyMatcher(propertyTest, messagePrefix) {
+ return function (property, value) {
+ assertType(property, "string", "property");
+ var onlyProperty = arguments.length === 1;
+ var message = messagePrefix + "(\"" + property + "\"";
+ if (!onlyProperty) {
+ message += ", " + value;
+ }
+ message += ")";
+ return match(function (actual) {
+ if (actual === undefined || actual === null ||
+ !propertyTest(actual, property)) {
+ return false;
+ }
+ return onlyProperty || sinon.deepEqual(value, actual[property]);
+ }, message);
+ };
+ }
+
+ match.has = createPropertyMatcher(function (actual, property) {
+ if (typeof actual === "object") {
+ return property in actual;
+ }
+ return actual[property] !== undefined;
+ }, "has");
+
+ match.hasOwn = createPropertyMatcher(function (actual, property) {
+ return actual.hasOwnProperty(property);
+ }, "hasOwn");
+
+ match.bool = match.typeOf("boolean");
+ match.number = match.typeOf("number");
+ match.string = match.typeOf("string");
+ match.object = match.typeOf("object");
+ match.func = match.typeOf("function");
+ match.array = match.typeOf("array");
+ match.regexp = match.typeOf("regexp");
+ match.date = match.typeOf("date");
+
+ if (commonJSModule) {
+ module.exports = match;
+ } else {
+ sinon.match = match;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend match.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Spy calls
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Maximilian Antoni (mail@maxantoni.de)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ * Copyright (c) 2013 Maximilian Antoni
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function throwYieldError(proxy, text, args) {
+ var msg = sinon.functionName(proxy) + text;
+ if (args.length) {
+ msg += " Received [" + slice.call(args).join(", ") + "]";
+ }
+ throw new Error(msg);
+ }
+
+ var slice = Array.prototype.slice;
+
+ var callProto = {
+ calledOn: function calledOn(thisValue) {
+ if (sinon.match && sinon.match.isMatcher(thisValue)) {
+ return thisValue.test(this.thisValue);
+ }
+ return this.thisValue === thisValue;
+ },
+
+ calledWith: function calledWith() {
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ calledWithMatch: function calledWithMatch() {
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
+ var actual = this.args[i];
+ var expectation = arguments[i];
+ if (!sinon.match || !sinon.match(expectation).test(actual)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ calledWithExactly: function calledWithExactly() {
+ return arguments.length == this.args.length &&
+ this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWith: function notCalledWith() {
+ return !this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWithMatch: function notCalledWithMatch() {
+ return !this.calledWithMatch.apply(this, arguments);
+ },
+
+ returned: function returned(value) {
+ return sinon.deepEqual(value, this.returnValue);
+ },
+
+ threw: function threw(error) {
+ if (typeof error === "undefined" || !this.exception) {
+ return !!this.exception;
+ }
+
+ return this.exception === error || this.exception.name === error;
+ },
+
+ calledWithNew: function calledWithNew() {
+ return this.proxy.prototype && this.thisValue instanceof this.proxy;
+ },
+
+ calledBefore: function (other) {
+ return this.callId < other.callId;
+ },
+
+ calledAfter: function (other) {
+ return this.callId > other.callId;
+ },
+
+ callArg: function (pos) {
+ this.args[pos]();
+ },
+
+ callArgOn: function (pos, thisValue) {
+ this.args[pos].apply(thisValue);
+ },
+
+ callArgWith: function (pos) {
+ this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
+ },
+
+ callArgOnWith: function (pos, thisValue) {
+ var args = slice.call(arguments, 2);
+ this.args[pos].apply(thisValue, args);
+ },
+
+ "yield": function () {
+ this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
+ },
+
+ yieldOn: function (thisValue) {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (typeof args[i] === "function") {
+ args[i].apply(thisValue, slice.call(arguments, 1));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+ },
+
+ yieldTo: function (prop) {
+ this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
+ },
+
+ yieldToOn: function (prop, thisValue) {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (args[i] && typeof args[i][prop] === "function") {
+ args[i][prop].apply(thisValue, slice.call(arguments, 2));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield to '" + prop +
+ "' since no callback was passed.", args);
+ },
+
+ toString: function () {
+ var callStr = this.proxy.toString() + "(";
+ var args = [];
+
+ for (var i = 0, l = this.args.length; i < l; ++i) {
+ args.push(sinon.format(this.args[i]));
+ }
+
+ callStr = callStr + args.join(", ") + ")";
+
+ if (typeof this.returnValue != "undefined") {
+ callStr += " => " + sinon.format(this.returnValue);
+ }
+
+ if (this.exception) {
+ callStr += " !" + this.exception.name;
+
+ if (this.exception.message) {
+ callStr += "(" + this.exception.message + ")";
+ }
+ }
+
+ return callStr;
+ }
+ };
+
+ callProto.invokeCallback = callProto.yield;
+
+ function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
+ if (typeof id !== "number") {
+ throw new TypeError("Call id is not a number");
+ }
+ var proxyCall = sinon.create(callProto);
+ proxyCall.proxy = spy;
+ proxyCall.thisValue = thisValue;
+ proxyCall.args = args;
+ proxyCall.returnValue = returnValue;
+ proxyCall.exception = exception;
+ proxyCall.callId = id;
+
+ return proxyCall;
+ }
+ createSpyCall.toString = callProto.toString; // used by mocks
+
+ if (commonJSModule) {
+ module.exports = createSpyCall;
+ } else {
+ sinon.spyCall = createSpyCall;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+
+/**
+ * @depend ../sinon.js
+ * @depend call.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Spy functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+ var push = Array.prototype.push;
+ var slice = Array.prototype.slice;
+ var callId = 0;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function spy(object, property) {
+ if (!property && typeof object == "function") {
+ return spy.create(object);
+ }
+
+ if (!object && !property) {
+ return spy.create(function () { });
+ }
+
+ var method = object[property];
+ return sinon.wrapMethod(object, property, spy.create(method));
+ }
+
+ function matchingFake(fakes, args, strict) {
+ if (!fakes) {
+ return;
+ }
+
+ for (var i = 0, l = fakes.length; i < l; i++) {
+ if (fakes[i].matches(args, strict)) {
+ return fakes[i];
+ }
+ }
+ }
+
+ function incrementCallCount() {
+ this.called = true;
+ this.callCount += 1;
+ this.notCalled = false;
+ this.calledOnce = this.callCount == 1;
+ this.calledTwice = this.callCount == 2;
+ this.calledThrice = this.callCount == 3;
+ }
+
+ function createCallProperties() {
+ this.firstCall = this.getCall(0);
+ this.secondCall = this.getCall(1);
+ this.thirdCall = this.getCall(2);
+ this.lastCall = this.getCall(this.callCount - 1);
+ }
+
+ var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
+ function createProxy(func) {
+ // Retain the function length:
+ var p;
+ if (func.length) {
+ eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
+ ") { return p.invoke(func, this, slice.call(arguments)); });");
+ }
+ else {
+ p = function proxy() {
+ return p.invoke(func, this, slice.call(arguments));
+ };
+ }
+ return p;
+ }
+
+ var uuid = 0;
+
+ // Public API
+ var spyApi = {
+ reset: function () {
+ this.called = false;
+ this.notCalled = true;
+ this.calledOnce = false;
+ this.calledTwice = false;
+ this.calledThrice = false;
+ this.callCount = 0;
+ this.firstCall = null;
+ this.secondCall = null;
+ this.thirdCall = null;
+ this.lastCall = null;
+ this.args = [];
+ this.returnValues = [];
+ this.thisValues = [];
+ this.exceptions = [];
+ this.callIds = [];
+ if (this.fakes) {
+ for (var i = 0; i < this.fakes.length; i++) {
+ this.fakes[i].reset();
+ }
+ }
+ },
+
+ create: function create(func) {
+ var name;
+
+ if (typeof func != "function") {
+ func = function () { };
+ } else {
+ name = sinon.functionName(func);
+ }
+
+ var proxy = createProxy(func);
+
+ sinon.extend(proxy, spy);
+ delete proxy.create;
+ sinon.extend(proxy, func);
+
+ proxy.reset();
+ proxy.prototype = func.prototype;
+ proxy.displayName = name || "spy";
+ proxy.toString = sinon.functionToString;
+ proxy._create = sinon.spy.create;
+ proxy.id = "spy#" + uuid++;
+
+ return proxy;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ var matching = matchingFake(this.fakes, args);
+ var exception, returnValue;
+
+ incrementCallCount.call(this);
+ push.call(this.thisValues, thisValue);
+ push.call(this.args, args);
+ push.call(this.callIds, callId++);
+
+ try {
+ if (matching) {
+ returnValue = matching.invoke(func, thisValue, args);
+ } else {
+ returnValue = (this.func || func).apply(thisValue, args);
+ }
+
+ var thisCall = this.getCall(this.callCount - 1);
+ if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
+ returnValue = thisValue;
+ }
+ } catch (e) {
+ exception = e;
+ }
+
+ push.call(this.exceptions, exception);
+ push.call(this.returnValues, returnValue);
+
+ createCallProperties.call(this);
+
+ if (exception !== undefined) {
+ throw exception;
+ }
+
+ return returnValue;
+ },
+
+ getCall: function getCall(i) {
+ if (i < 0 || i >= this.callCount) {
+ return null;
+ }
+
+ return sinon.spyCall(this, this.thisValues[i], this.args[i],
+ this.returnValues[i], this.exceptions[i],
+ this.callIds[i]);
+ },
+
+ getCalls: function () {
+ var calls = [];
+ var i;
+
+ for (i = 0; i < this.callCount; i++) {
+ calls.push(this.getCall(i));
+ }
+
+ return calls;
+ },
+
+ calledBefore: function calledBefore(spyFn) {
+ if (!this.called) {
+ return false;
+ }
+
+ if (!spyFn.called) {
+ return true;
+ }
+
+ return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+ },
+
+ calledAfter: function calledAfter(spyFn) {
+ if (!this.called || !spyFn.called) {
+ return false;
+ }
+
+ return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+ },
+
+ withArgs: function () {
+ var args = slice.call(arguments);
+
+ if (this.fakes) {
+ var match = matchingFake(this.fakes, args, true);
+
+ if (match) {
+ return match;
+ }
+ } else {
+ this.fakes = [];
+ }
+
+ var original = this;
+ var fake = this._create();
+ fake.matchingArguments = args;
+ fake.parent = this;
+ push.call(this.fakes, fake);
+
+ fake.withArgs = function () {
+ return original.withArgs.apply(original, arguments);
+ };
+
+ for (var i = 0; i < this.args.length; i++) {
+ if (fake.matches(this.args[i])) {
+ incrementCallCount.call(fake);
+ push.call(fake.thisValues, this.thisValues[i]);
+ push.call(fake.args, this.args[i]);
+ push.call(fake.returnValues, this.returnValues[i]);
+ push.call(fake.exceptions, this.exceptions[i]);
+ push.call(fake.callIds, this.callIds[i]);
+ }
+ }
+ createCallProperties.call(fake);
+
+ return fake;
+ },
+
+ matches: function (args, strict) {
+ var margs = this.matchingArguments;
+
+ if (margs.length <= args.length &&
+ sinon.deepEqual(margs, args.slice(0, margs.length))) {
+ return !strict || margs.length == args.length;
+ }
+ },
+
+ printf: function (format) {
+ var spy = this;
+ var args = slice.call(arguments, 1);
+ var formatter;
+
+ return (format || "").replace(/%(.)/g, function (match, specifier) {
+ formatter = spyApi.formatters[specifier];
+
+ if (typeof formatter == "function") {
+ return formatter.call(null, spy, args);
+ } else if (!isNaN(parseInt(specifier, 10))) {
+ return sinon.format(args[specifier - 1]);
+ }
+
+ return "%" + specifier;
+ });
+ }
+ };
+
+ function delegateToCalls(method, matchAny, actual, notCalled) {
+ spyApi[method] = function () {
+ if (!this.called) {
+ if (notCalled) {
+ return notCalled.apply(this, arguments);
+ }
+ return false;
+ }
+
+ var currentCall;
+ var matches = 0;
+
+ for (var i = 0, l = this.callCount; i < l; i += 1) {
+ currentCall = this.getCall(i);
+
+ if (currentCall[actual || method].apply(currentCall, arguments)) {
+ matches += 1;
+
+ if (matchAny) {
+ return true;
+ }
+ }
+ }
+
+ return matches === this.callCount;
+ };
+ }
+
+ delegateToCalls("calledOn", true);
+ delegateToCalls("alwaysCalledOn", false, "calledOn");
+ delegateToCalls("calledWith", true);
+ delegateToCalls("calledWithMatch", true);
+ delegateToCalls("alwaysCalledWith", false, "calledWith");
+ delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
+ delegateToCalls("calledWithExactly", true);
+ delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
+ delegateToCalls("neverCalledWith", false, "notCalledWith",
+ function () { return true; });
+ delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
+ function () { return true; });
+ delegateToCalls("threw", true);
+ delegateToCalls("alwaysThrew", false, "threw");
+ delegateToCalls("returned", true);
+ delegateToCalls("alwaysReturned", false, "returned");
+ delegateToCalls("calledWithNew", true);
+ delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
+ delegateToCalls("callArg", false, "callArgWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+ });
+ spyApi.callArgWith = spyApi.callArg;
+ delegateToCalls("callArgOn", false, "callArgOnWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+ });
+ spyApi.callArgOnWith = spyApi.callArgOn;
+ delegateToCalls("yield", false, "yield", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+ });
+ // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+ spyApi.invokeCallback = spyApi.yield;
+ delegateToCalls("yieldOn", false, "yieldOn", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+ });
+ delegateToCalls("yieldTo", false, "yieldTo", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + property +
+ "' since it was not yet invoked.");
+ });
+ delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + property +
+ "' since it was not yet invoked.");
+ });
+
+ spyApi.formatters = {
+ "c": function (spy) {
+ return sinon.timesInWords(spy.callCount);
+ },
+
+ "n": function (spy) {
+ return spy.toString();
+ },
+
+ "C": function (spy) {
+ var calls = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ var stringifiedCall = " " + spy.getCall(i).toString();
+ if (/\n/.test(calls[i - 1])) {
+ stringifiedCall = "\n" + stringifiedCall;
+ }
+ push.call(calls, stringifiedCall);
+ }
+
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
+ },
+
+ "t": function (spy) {
+ var objects = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ push.call(objects, sinon.format(spy.thisValues[i]));
+ }
+
+ return objects.join(", ");
+ },
+
+ "*": function (spy, args) {
+ var formatted = [];
+
+ for (var i = 0, l = args.length; i < l; ++i) {
+ push.call(formatted, sinon.format(args[i]));
+ }
+
+ return formatted.join(", ");
+ }
+ };
+
+ sinon.extend(spy, spyApi);
+
+ spy.spyCall = sinon.spyCall;
+
+ if (commonJSModule) {
+ module.exports = spy;
+ } else {
+ sinon.spy = spy;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global module, require, sinon, process, setImmediate, setTimeout*/
+/**
+ * Stub behavior
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Tim Fischbach (mail@timfischbach.de)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ var slice = Array.prototype.slice;
+ var join = Array.prototype.join;
+ var proto;
+
+ var nextTick = (function () {
+ if (typeof process === "object" && typeof process.nextTick === "function") {
+ return process.nextTick;
+ } else if (typeof setImmediate === "function") {
+ return setImmediate;
+ } else {
+ return function (callback) {
+ setTimeout(callback, 0);
+ };
+ }
+ })();
+
+ function throwsException(error, message) {
+ if (typeof error == "string") {
+ this.exception = new Error(message || "");
+ this.exception.name = error;
+ } else if (!error) {
+ this.exception = new Error("Error");
+ } else {
+ this.exception = error;
+ }
+
+ return this;
+ }
+
+ function getCallback(behavior, args) {
+ var callArgAt = behavior.callArgAt;
+
+ if (callArgAt < 0) {
+ var callArgProp = behavior.callArgProp;
+
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (!callArgProp && typeof args[i] == "function") {
+ return args[i];
+ }
+
+ if (callArgProp && args[i] &&
+ typeof args[i][callArgProp] == "function") {
+ return args[i][callArgProp];
+ }
+ }
+
+ return null;
+ }
+
+ return args[callArgAt];
+ }
+
+ function getCallbackError(behavior, func, args) {
+ if (behavior.callArgAt < 0) {
+ var msg;
+
+ if (behavior.callArgProp) {
+ msg = sinon.functionName(behavior.stub) +
+ " expected to yield to '" + behavior.callArgProp +
+ "', but no object with such a property was passed.";
+ } else {
+ msg = sinon.functionName(behavior.stub) +
+ " expected to yield, but no callback was passed.";
+ }
+
+ if (args.length > 0) {
+ msg += " Received [" + join.call(args, ", ") + "]";
+ }
+
+ return msg;
+ }
+
+ return "argument at index " + behavior.callArgAt + " is not a function: " + func;
+ }
+
+ function callCallback(behavior, args) {
+ if (typeof behavior.callArgAt == "number") {
+ var func = getCallback(behavior, args);
+
+ if (typeof func != "function") {
+ throw new TypeError(getCallbackError(behavior, func, args));
+ }
+
+ if (behavior.callbackAsync) {
+ nextTick(function() {
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
+ });
+ } else {
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
+ }
+ }
+ }
+
+ proto = {
+ create: function(stub) {
+ var behavior = sinon.extend({}, sinon.behavior);
+ delete behavior.create;
+ behavior.stub = stub;
+
+ return behavior;
+ },
+
+ isPresent: function() {
+ return (typeof this.callArgAt == 'number' ||
+ this.exception ||
+ typeof this.returnArgAt == 'number' ||
+ this.returnThis ||
+ this.returnValueDefined);
+ },
+
+ invoke: function(context, args) {
+ callCallback(this, args);
+
+ if (this.exception) {
+ throw this.exception;
+ } else if (typeof this.returnArgAt == 'number') {
+ return args[this.returnArgAt];
+ } else if (this.returnThis) {
+ return context;
+ }
+
+ return this.returnValue;
+ },
+
+ onCall: function(index) {
+ return this.stub.onCall(index);
+ },
+
+ onFirstCall: function() {
+ return this.stub.onFirstCall();
+ },
+
+ onSecondCall: function() {
+ return this.stub.onSecondCall();
+ },
+
+ onThirdCall: function() {
+ return this.stub.onThirdCall();
+ },
+
+ withArgs: function(/* arguments */) {
+ throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
+ 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
+ },
+
+ callsArg: function callsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = [];
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ callsArgOn: function callsArgOn(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = [];
+ this.callbackContext = context;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ callsArgWith: function callsArgWith(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ callsArgOnWith: function callsArgWith(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = slice.call(arguments, 2);
+ this.callbackContext = context;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yields: function () {
+ this.callArgAt = -1;
+ this.callbackArguments = slice.call(arguments, 0);
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsOn: function (context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = -1;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = context;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsTo: function (prop) {
+ this.callArgAt = -1;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = undefined;
+ this.callArgProp = prop;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsToOn: function (prop, context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = -1;
+ this.callbackArguments = slice.call(arguments, 2);
+ this.callbackContext = context;
+ this.callArgProp = prop;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+
+ "throws": throwsException,
+ throwsException: throwsException,
+
+ returns: function returns(value) {
+ this.returnValue = value;
+ this.returnValueDefined = true;
+
+ return this;
+ },
+
+ returnsArg: function returnsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.returnArgAt = pos;
+
+ return this;
+ },
+
+ returnsThis: function returnsThis() {
+ this.returnThis = true;
+
+ return this;
+ }
+ };
+
+ // create asynchronous versions of callsArg* and yields* methods
+ for (var method in proto) {
+ // need to avoid creating anotherasync versions of the newly added async methods
+ if (proto.hasOwnProperty(method) &&
+ method.match(/^(callsArg|yields)/) &&
+ !method.match(/Async/)) {
+ proto[method + 'Async'] = (function (syncFnName) {
+ return function () {
+ var result = this[syncFnName].apply(this, arguments);
+ this.callbackAsync = true;
+ return result;
+ };
+ })(method);
+ }
+ }
+
+ if (commonJSModule) {
+ module.exports = proto;
+ } else {
+ sinon.behavior = proto;
+ }
+}(typeof sinon == "object" && sinon || null));
+/**
+ * @depend ../sinon.js
+ * @depend spy.js
+ * @depend behavior.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global module, require, sinon*/
+/**
+ * Stub functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function stub(object, property, func) {
+ if (!!func && typeof func != "function") {
+ throw new TypeError("Custom stub should be function");
+ }
+
+ var wrapper;
+
+ if (func) {
+ wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
+ } else {
+ wrapper = stub.create();
+ }
+
+ if (!object && typeof property === "undefined") {
+ return sinon.stub.create();
+ }
+
+ if (typeof property === "undefined" && typeof object == "object") {
+ for (var prop in object) {
+ if (typeof object[prop] === "function") {
+ stub(object, prop);
+ }
+ }
+
+ return object;
+ }
+
+ return sinon.wrapMethod(object, property, wrapper);
+ }
+
+ function getDefaultBehavior(stub) {
+ return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
+ }
+
+ function getParentBehaviour(stub) {
+ return (stub.parent && getCurrentBehavior(stub.parent));
+ }
+
+ function getCurrentBehavior(stub) {
+ var behavior = stub.behaviors[stub.callCount - 1];
+ return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
+ }
+
+ var uuid = 0;
+
+ sinon.extend(stub, (function () {
+ var proto = {
+ create: function create() {
+ var functionStub = function () {
+ return getCurrentBehavior(functionStub).invoke(this, arguments);
+ };
+
+ functionStub.id = "stub#" + uuid++;
+ var orig = functionStub;
+ functionStub = sinon.spy.create(functionStub);
+ functionStub.func = orig;
+
+ sinon.extend(functionStub, stub);
+ functionStub._create = sinon.stub.create;
+ functionStub.displayName = "stub";
+ functionStub.toString = sinon.functionToString;
+
+ functionStub.defaultBehavior = null;
+ functionStub.behaviors = [];
+
+ return functionStub;
+ },
+
+ resetBehavior: function () {
+ var i;
+
+ this.defaultBehavior = null;
+ this.behaviors = [];
+
+ delete this.returnValue;
+ delete this.returnArgAt;
+ this.returnThis = false;
+
+ if (this.fakes) {
+ for (i = 0; i < this.fakes.length; i++) {
+ this.fakes[i].resetBehavior();
+ }
+ }
+ },
+
+ onCall: function(index) {
+ if (!this.behaviors[index]) {
+ this.behaviors[index] = sinon.behavior.create(this);
+ }
+
+ return this.behaviors[index];
+ },
+
+ onFirstCall: function() {
+ return this.onCall(0);
+ },
+
+ onSecondCall: function() {
+ return this.onCall(1);
+ },
+
+ onThirdCall: function() {
+ return this.onCall(2);
+ }
+ };
+
+ for (var method in sinon.behavior) {
+ if (sinon.behavior.hasOwnProperty(method) &&
+ !proto.hasOwnProperty(method) &&
+ method != 'create' &&
+ method != 'withArgs' &&
+ method != 'invoke') {
+ proto[method] = (function(behaviorMethod) {
+ return function() {
+ this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
+ this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
+ return this;
+ };
+ }(method));
+ }
+ }
+
+ return proto;
+ }()));
+
+ if (commonJSModule) {
+ module.exports = stub;
+ } else {
+ sinon.stub = stub;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false*/
+/*global module, require, sinon*/
+/**
+ * Mock functions.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+ var push = [].push;
+ var match;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ match = sinon.match;
+
+ if (!match && commonJSModule) {
+ match = require("./match");
+ }
+
+ function mock(object) {
+ if (!object) {
+ return sinon.expectation.create("Anonymous mock");
+ }
+
+ return mock.create(object);
+ }
+
+ sinon.mock = mock;
+
+ sinon.extend(mock, (function () {
+ function each(collection, callback) {
+ if (!collection) {
+ return;
+ }
+
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+
+ return {
+ create: function create(object) {
+ if (!object) {
+ throw new TypeError("object is null");
+ }
+
+ var mockObject = sinon.extend({}, mock);
+ mockObject.object = object;
+ delete mockObject.create;
+
+ return mockObject;
+ },
+
+ expects: function expects(method) {
+ if (!method) {
+ throw new TypeError("method is falsy");
+ }
+
+ if (!this.expectations) {
+ this.expectations = {};
+ this.proxies = [];
+ }
+
+ if (!this.expectations[method]) {
+ this.expectations[method] = [];
+ var mockObject = this;
+
+ sinon.wrapMethod(this.object, method, function () {
+ return mockObject.invokeMethod(method, this, arguments);
+ });
+
+ push.call(this.proxies, method);
+ }
+
+ var expectation = sinon.expectation.create(method);
+ push.call(this.expectations[method], expectation);
+
+ return expectation;
+ },
+
+ restore: function restore() {
+ var object = this.object;
+
+ each(this.proxies, function (proxy) {
+ if (typeof object[proxy].restore == "function") {
+ object[proxy].restore();
+ }
+ });
+ },
+
+ verify: function verify() {
+ var expectations = this.expectations || {};
+ var messages = [], met = [];
+
+ each(this.proxies, function (proxy) {
+ each(expectations[proxy], function (expectation) {
+ if (!expectation.met()) {
+ push.call(messages, expectation.toString());
+ } else {
+ push.call(met, expectation.toString());
+ }
+ });
+ });
+
+ this.restore();
+
+ if (messages.length > 0) {
+ sinon.expectation.fail(messages.concat(met).join("\n"));
+ } else {
+ sinon.expectation.pass(messages.concat(met).join("\n"));
+ }
+
+ return true;
+ },
+
+ invokeMethod: function invokeMethod(method, thisValue, args) {
+ var expectations = this.expectations && this.expectations[method];
+ var length = expectations && expectations.length || 0, i;
+
+ for (i = 0; i < length; i += 1) {
+ if (!expectations[i].met() &&
+ expectations[i].allowsCall(thisValue, args)) {
+ return expectations[i].apply(thisValue, args);
+ }
+ }
+
+ var messages = [], available, exhausted = 0;
+
+ for (i = 0; i < length; i += 1) {
+ if (expectations[i].allowsCall(thisValue, args)) {
+ available = available || expectations[i];
+ } else {
+ exhausted += 1;
+ }
+ push.call(messages, " " + expectations[i].toString());
+ }
+
+ if (exhausted === 0) {
+ return available.apply(thisValue, args);
+ }
+
+ messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
+ proxy: method,
+ args: args
+ }));
+
+ sinon.expectation.fail(messages.join("\n"));
+ }
+ };
+ }()));
+
+ var times = sinon.timesInWords;
+
+ sinon.expectation = (function () {
+ var slice = Array.prototype.slice;
+ var _invoke = sinon.spy.invoke;
+
+ function callCountInWords(callCount) {
+ if (callCount == 0) {
+ return "never called";
+ } else {
+ return "called " + times(callCount);
+ }
+ }
+
+ function expectedCallCountInWords(expectation) {
+ var min = expectation.minCalls;
+ var max = expectation.maxCalls;
+
+ if (typeof min == "number" && typeof max == "number") {
+ var str = times(min);
+
+ if (min != max) {
+ str = "at least " + str + " and at most " + times(max);
+ }
+
+ return str;
+ }
+
+ if (typeof min == "number") {
+ return "at least " + times(min);
+ }
+
+ return "at most " + times(max);
+ }
+
+ function receivedMinCalls(expectation) {
+ var hasMinLimit = typeof expectation.minCalls == "number";
+ return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+ }
+
+ function receivedMaxCalls(expectation) {
+ if (typeof expectation.maxCalls != "number") {
+ return false;
+ }
+
+ return expectation.callCount == expectation.maxCalls;
+ }
+
+ function verifyMatcher(possibleMatcher, arg){
+ if (match && match.isMatcher(possibleMatcher)) {
+ return possibleMatcher.test(arg);
+ } else {
+ return true;
+ }
+ }
+
+ return {
+ minCalls: 1,
+ maxCalls: 1,
+
+ create: function create(methodName) {
+ var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
+ delete expectation.create;
+ expectation.method = methodName;
+
+ return expectation;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ this.verifyCallAllowed(thisValue, args);
+
+ return _invoke.apply(this, arguments);
+ },
+
+ atLeast: function atLeast(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.maxCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.minCalls = num;
+
+ return this;
+ },
+
+ atMost: function atMost(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.minCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.maxCalls = num;
+
+ return this;
+ },
+
+ never: function never() {
+ return this.exactly(0);
+ },
+
+ once: function once() {
+ return this.exactly(1);
+ },
+
+ twice: function twice() {
+ return this.exactly(2);
+ },
+
+ thrice: function thrice() {
+ return this.exactly(3);
+ },
+
+ exactly: function exactly(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not a number");
+ }
+
+ this.atLeast(num);
+ return this.atMost(num);
+ },
+
+ met: function met() {
+ return !this.failed && receivedMinCalls(this);
+ },
+
+ verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+ if (receivedMaxCalls(this)) {
+ this.failed = true;
+ sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
+ this.expectedThis);
+ }
+
+ if (!("expectedArguments" in this)) {
+ return;
+ }
+
+ if (!args) {
+ sinon.expectation.fail(this.method + " received no arguments, expected " +
+ sinon.format(this.expectedArguments));
+ }
+
+ if (args.length < this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
+ "), expected " + sinon.format(this.expectedArguments));
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
+ "), expected " + sinon.format(this.expectedArguments));
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+
+ if (!verifyMatcher(this.expectedArguments[i],args[i])) {
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+ ", didn't match " + this.expectedArguments.toString());
+ }
+
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+ ", expected " + sinon.format(this.expectedArguments));
+ }
+ }
+ },
+
+ allowsCall: function allowsCall(thisValue, args) {
+ if (this.met() && receivedMaxCalls(this)) {
+ return false;
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ return false;
+ }
+
+ if (!("expectedArguments" in this)) {
+ return true;
+ }
+
+ args = args || [];
+
+ if (args.length < this.expectedArguments.length) {
+ return false;
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ return false;
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+ if (!verifyMatcher(this.expectedArguments[i],args[i])) {
+ return false;
+ }
+
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ withArgs: function withArgs() {
+ this.expectedArguments = slice.call(arguments);
+ return this;
+ },
+
+ withExactArgs: function withExactArgs() {
+ this.withArgs.apply(this, arguments);
+ this.expectsExactArgCount = true;
+ return this;
+ },
+
+ on: function on(thisValue) {
+ this.expectedThis = thisValue;
+ return this;
+ },
+
+ toString: function () {
+ var args = (this.expectedArguments || []).slice();
+
+ if (!this.expectsExactArgCount) {
+ push.call(args, "[...]");
+ }
+
+ var callStr = sinon.spyCall.toString.call({
+ proxy: this.method || "anonymous mock expectation",
+ args: args
+ });
+
+ var message = callStr.replace(", [...", "[, ...") + " " +
+ expectedCallCountInWords(this);
+
+ if (this.met()) {
+ return "Expectation met: " + message;
+ }
+
+ return "Expected " + message + " (" +
+ callCountInWords(this.callCount) + ")";
+ },
+
+ verify: function verify() {
+ if (!this.met()) {
+ sinon.expectation.fail(this.toString());
+ } else {
+ sinon.expectation.pass(this.toString());
+ }
+
+ return true;
+ },
+
+ pass: function(message) {
+ sinon.assert.pass(message);
+ },
+ fail: function (message) {
+ var exception = new Error(message);
+ exception.name = "ExpectationError";
+
+ throw exception;
+ }
+ };
+ }());
+
+ if (commonJSModule) {
+ module.exports = mock;
+ } else {
+ sinon.mock = mock;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true*/
+/*global module, require, sinon*/
+/**
+ * Collections of stubs, spies and mocks.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+ var push = [].push;
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function getFakes(fakeCollection) {
+ if (!fakeCollection.fakes) {
+ fakeCollection.fakes = [];
+ }
+
+ return fakeCollection.fakes;
+ }
+
+ function each(fakeCollection, method) {
+ var fakes = getFakes(fakeCollection);
+
+ for (var i = 0, l = fakes.length; i < l; i += 1) {
+ if (typeof fakes[i][method] == "function") {
+ fakes[i][method]();
+ }
+ }
+ }
+
+ function compact(fakeCollection) {
+ var fakes = getFakes(fakeCollection);
+ var i = 0;
+ while (i < fakes.length) {
+ fakes.splice(i, 1);
+ }
+ }
+
+ var collection = {
+ verify: function resolve() {
+ each(this, "verify");
+ },
+
+ restore: function restore() {
+ each(this, "restore");
+ compact(this);
+ },
+
+ verifyAndRestore: function verifyAndRestore() {
+ var exception;
+
+ try {
+ this.verify();
+ } catch (e) {
+ exception = e;
+ }
+
+ this.restore();
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ add: function add(fake) {
+ push.call(getFakes(this), fake);
+ return fake;
+ },
+
+ spy: function spy() {
+ return this.add(sinon.spy.apply(sinon, arguments));
+ },
+
+ stub: function stub(object, property, value) {
+ if (property) {
+ var original = object[property];
+
+ if (typeof original != "function") {
+ if (!hasOwnProperty.call(object, property)) {
+ throw new TypeError("Cannot stub non-existent own property " + property);
+ }
+
+ object[property] = value;
+
+ return this.add({
+ restore: function () {
+ object[property] = original;
+ }
+ });
+ }
+ }
+ if (!property && !!object && typeof object == "object") {
+ var stubbedObj = sinon.stub.apply(sinon, arguments);
+
+ for (var prop in stubbedObj) {
+ if (typeof stubbedObj[prop] === "function") {
+ this.add(stubbedObj[prop]);
+ }
+ }
+
+ return stubbedObj;
+ }
+
+ return this.add(sinon.stub.apply(sinon, arguments));
+ },
+
+ mock: function mock() {
+ return this.add(sinon.mock.apply(sinon, arguments));
+ },
+
+ inject: function inject(obj) {
+ var col = this;
+
+ obj.spy = function () {
+ return col.spy.apply(col, arguments);
+ };
+
+ obj.stub = function () {
+ return col.stub.apply(col, arguments);
+ };
+
+ obj.mock = function () {
+ return col.mock.apply(col, arguments);
+ };
+
+ return obj;
+ }
+ };
+
+ if (commonJSModule) {
+ module.exports = collection;
+ } else {
+ sinon.collection = collection;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
+/*global module, require, window*/
+/**
+ * Fake timer API
+ * setTimeout
+ * setInterval
+ * clearTimeout
+ * clearInterval
+ * tick
+ * reset
+ * Date
+ *
+ * Inspired by jsUnitMockTimeOut from JsUnit
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+(function (global) {
+ // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
+ // browsers, a number.
+ // see https://github.com/cjohansen/Sinon.JS/pull/436
+ var timeoutResult = setTimeout(function() {}, 0);
+ var addTimerReturnsObject = typeof timeoutResult === 'object';
+ clearTimeout(timeoutResult);
+
+ var id = 1;
+
+ function addTimer(args, recurring) {
+ if (args.length === 0) {
+ throw new Error("Function requires at least 1 parameter");
+ }
+
+ if (typeof args[0] === "undefined") {
+ throw new Error("Callback must be provided to timer calls");
+ }
+
+ var toId = id++;
+ var delay = args[1] || 0;
+
+ if (!this.timeouts) {
+ this.timeouts = {};
+ }
+
+ this.timeouts[toId] = {
+ id: toId,
+ func: args[0],
+ callAt: this.now + delay,
+ invokeArgs: Array.prototype.slice.call(args, 2)
+ };
+
+ if (recurring === true) {
+ this.timeouts[toId].interval = delay;
+ }
+
+ if (addTimerReturnsObject) {
+ return {
+ id: toId,
+ ref: function() {},
+ unref: function() {}
+ };
+ }
+ else {
+ return toId;
+ }
+ }
+
+ function parseTime(str) {
+ if (!str) {
+ return 0;
+ }
+
+ var strings = str.split(":");
+ var l = strings.length, i = l;
+ var ms = 0, parsed;
+
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+ throw new Error("tick only understands numbers and 'h:m:s'");
+ }
+
+ while (i--) {
+ parsed = parseInt(strings[i], 10);
+
+ if (parsed >= 60) {
+ throw new Error("Invalid time " + str);
+ }
+
+ ms += parsed * Math.pow(60, (l - i - 1));
+ }
+
+ return ms * 1000;
+ }
+
+ function createObject(object) {
+ var newObject;
+
+ if (Object.create) {
+ newObject = Object.create(object);
+ } else {
+ var F = function () {};
+ F.prototype = object;
+ newObject = new F();
+ }
+
+ newObject.Date.clock = newObject;
+ return newObject;
+ }
+
+ sinon.clock = {
+ now: 0,
+
+ create: function create(now) {
+ var clock = createObject(this);
+
+ if (typeof now == "number") {
+ clock.now = now;
+ }
+
+ if (!!now && typeof now == "object") {
+ throw new TypeError("now should be milliseconds since UNIX epoch");
+ }
+
+ return clock;
+ },
+
+ setTimeout: function setTimeout(callback, timeout) {
+ return addTimer.call(this, arguments, false);
+ },
+
+ clearTimeout: function clearTimeout(timerId) {
+ if (!this.timeouts) {
+ this.timeouts = [];
+ }
+
+ if (timerId in this.timeouts) {
+ delete this.timeouts[timerId];
+ }
+ },
+
+ setInterval: function setInterval(callback, timeout) {
+ return addTimer.call(this, arguments, true);
+ },
+
+ clearInterval: function clearInterval(timerId) {
+ this.clearTimeout(timerId);
+ },
+
+ setImmediate: function setImmediate(callback) {
+ var passThruArgs = Array.prototype.slice.call(arguments, 1);
+
+ return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
+ },
+
+ clearImmediate: function clearImmediate(timerId) {
+ this.clearTimeout(timerId);
+ },
+
+ tick: function tick(ms) {
+ ms = typeof ms == "number" ? ms : parseTime(ms);
+ var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
+ var timer = this.firstTimerInRange(tickFrom, tickTo);
+
+ var firstException;
+ while (timer && tickFrom <= tickTo) {
+ if (this.timeouts[timer.id]) {
+ tickFrom = this.now = timer.callAt;
+ try {
+ this.callTimer(timer);
+ } catch (e) {
+ firstException = firstException || e;
+ }
+ }
+
+ timer = this.firstTimerInRange(previous, tickTo);
+ previous = tickFrom;
+ }
+
+ this.now = tickTo;
+
+ if (firstException) {
+ throw firstException;
+ }
+
+ return this.now;
+ },
+
+ firstTimerInRange: function (from, to) {
+ var timer, smallest = null, originalTimer;
+
+ for (var id in this.timeouts) {
+ if (this.timeouts.hasOwnProperty(id)) {
+ if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
+ continue;
+ }
+
+ if (smallest === null || this.timeouts[id].callAt < smallest) {
+ originalTimer = this.timeouts[id];
+ smallest = this.timeouts[id].callAt;
+
+ timer = {
+ func: this.timeouts[id].func,
+ callAt: this.timeouts[id].callAt,
+ interval: this.timeouts[id].interval,
+ id: this.timeouts[id].id,
+ invokeArgs: this.timeouts[id].invokeArgs
+ };
+ }
+ }
+ }
+
+ return timer || null;
+ },
+
+ callTimer: function (timer) {
+ if (typeof timer.interval == "number") {
+ this.timeouts[timer.id].callAt += timer.interval;
+ } else {
+ delete this.timeouts[timer.id];
+ }
+
+ try {
+ if (typeof timer.func == "function") {
+ timer.func.apply(null, timer.invokeArgs);
+ } else {
+ eval(timer.func);
+ }
+ } catch (e) {
+ var exception = e;
+ }
+
+ if (!this.timeouts[timer.id]) {
+ if (exception) {
+ throw exception;
+ }
+ return;
+ }
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ reset: function reset() {
+ this.timeouts = {};
+ },
+
+ Date: (function () {
+ var NativeDate = Date;
+
+ function ClockDate(year, month, date, hour, minute, second, ms) {
+ // Defensive and verbose to avoid potential harm in passing
+ // explicit undefined when user does not pass argument
+ switch (arguments.length) {
+ case 0:
+ return new NativeDate(ClockDate.clock.now);
+ case 1:
+ return new NativeDate(year);
+ case 2:
+ return new NativeDate(year, month);
+ case 3:
+ return new NativeDate(year, month, date);
+ case 4:
+ return new NativeDate(year, month, date, hour);
+ case 5:
+ return new NativeDate(year, month, date, hour, minute);
+ case 6:
+ return new NativeDate(year, month, date, hour, minute, second);
+ default:
+ return new NativeDate(year, month, date, hour, minute, second, ms);
+ }
+ }
+
+ return mirrorDateProperties(ClockDate, NativeDate);
+ }())
+ };
+
+ function mirrorDateProperties(target, source) {
+ if (source.now) {
+ target.now = function now() {
+ return target.clock.now;
+ };
+ } else {
+ delete target.now;
+ }
+
+ if (source.toSource) {
+ target.toSource = function toSource() {
+ return source.toSource();
+ };
+ } else {
+ delete target.toSource;
+ }
+
+ target.toString = function toString() {
+ return source.toString();
+ };
+
+ target.prototype = source.prototype;
+ target.parse = source.parse;
+ target.UTC = source.UTC;
+ target.prototype.toUTCString = source.prototype.toUTCString;
+
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+
+ return target;
+ }
+
+ var methods = ["Date", "setTimeout", "setInterval",
+ "clearTimeout", "clearInterval"];
+
+ if (typeof global.setImmediate !== "undefined") {
+ methods.push("setImmediate");
+ }
+
+ if (typeof global.clearImmediate !== "undefined") {
+ methods.push("clearImmediate");
+ }
+
+ function restore() {
+ var method;
+
+ for (var i = 0, l = this.methods.length; i < l; i++) {
+ method = this.methods[i];
+
+ if (global[method].hadOwnProperty) {
+ global[method] = this["_" + method];
+ } else {
+ try {
+ delete global[method];
+ } catch (e) {}
+ }
+ }
+
+ // Prevent multiple executions which will completely remove these props
+ this.methods = [];
+ }
+
+ function stubGlobal(method, clock) {
+ clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
+ clock["_" + method] = global[method];
+
+ if (method == "Date") {
+ var date = mirrorDateProperties(clock[method], global[method]);
+ global[method] = date;
+ } else {
+ global[method] = function () {
+ return clock[method].apply(clock, arguments);
+ };
+
+ for (var prop in clock[method]) {
+ if (clock[method].hasOwnProperty(prop)) {
+ global[method][prop] = clock[method][prop];
+ }
+ }
+ }
+
+ global[method].clock = clock;
+ }
+
+ sinon.useFakeTimers = function useFakeTimers(now) {
+ var clock = sinon.clock.create(now);
+ clock.restore = restore;
+ clock.methods = Array.prototype.slice.call(arguments,
+ typeof now == "number" ? 1 : 0);
+
+ if (clock.methods.length === 0) {
+ clock.methods = methods;
+ }
+
+ for (var i = 0, l = clock.methods.length; i < l; i++) {
+ stubGlobal(clock.methods[i], clock);
+ }
+
+ return clock;
+ };
+}(typeof global != "undefined" && typeof global !== "function" ? global : this));
+
+sinon.timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+ clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+};
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = sinon;
+}
+
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Minimal Event interface implementation
+ *
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
+ * Modifications and tests by Christian Johansen.
+ *
+ * @author Sven Fuchs (svenfuchs@artweb-design.de)
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+
+(function () {
+ var push = [].push;
+
+ sinon.Event = function Event(type, bubbles, cancelable, target) {
+ this.initEvent(type, bubbles, cancelable, target);
+ };
+
+ sinon.Event.prototype = {
+ initEvent: function(type, bubbles, cancelable, target) {
+ this.type = type;
+ this.bubbles = bubbles;
+ this.cancelable = cancelable;
+ this.target = target;
+ },
+
+ stopPropagation: function () {},
+
+ preventDefault: function () {
+ this.defaultPrevented = true;
+ }
+ };
+
+ sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
+ this.initEvent(type, false, false, target);
+ this.loaded = progressEventRaw.loaded || null;
+ this.total = progressEventRaw.total || null;
+ };
+
+ sinon.ProgressEvent.prototype = new sinon.Event();
+
+ sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
+
+ sinon.CustomEvent = function CustomEvent(type, customData, target) {
+ this.initEvent(type, false, false, target);
+ this.detail = customData.detail || null;
+ };
+
+ sinon.CustomEvent.prototype = new sinon.Event();
+
+ sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
+
+ sinon.EventTarget = {
+ addEventListener: function addEventListener(event, listener) {
+ this.eventListeners = this.eventListeners || {};
+ this.eventListeners[event] = this.eventListeners[event] || [];
+ push.call(this.eventListeners[event], listener);
+ },
+
+ removeEventListener: function removeEventListener(event, listener) {
+ var listeners = this.eventListeners && this.eventListeners[event] || [];
+
+ for (var i = 0, l = listeners.length; i < l; ++i) {
+ if (listeners[i] == listener) {
+ return listeners.splice(i, 1);
+ }
+ }
+ },
+
+ dispatchEvent: function dispatchEvent(event) {
+ var type = event.type;
+ var listeners = this.eventListeners && this.eventListeners[type] || [];
+
+ for (var i = 0; i < listeners.length; i++) {
+ if (typeof listeners[i] == "function") {
+ listeners[i].call(this, event);
+ } else {
+ listeners[i].handleEvent(event);
+ }
+ }
+
+ return !!event.defaultPrevented;
+ }
+ };
+}());
+
+/**
+ * @depend ../../sinon.js
+ * @depend event.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Fake XMLHttpRequest object
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+// wrapper for global
+(function(global) {
+ if (typeof sinon === "undefined") {
+ global.sinon = {};
+ }
+
+ var supportsProgress = typeof ProgressEvent !== "undefined";
+ var supportsCustomEvent = typeof CustomEvent !== "undefined";
+ sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
+ var xhr = sinon.xhr;
+ xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+ xhr.GlobalActiveXObject = global.ActiveXObject;
+ xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
+ xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
+ xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
+ ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
+ xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
+
+ /*jsl:ignore*/
+ var unsafeHeaders = {
+ "Accept-Charset": true,
+ "Accept-Encoding": true,
+ "Connection": true,
+ "Content-Length": true,
+ "Cookie": true,
+ "Cookie2": true,
+ "Content-Transfer-Encoding": true,
+ "Date": true,
+ "Expect": true,
+ "Host": true,
+ "Keep-Alive": true,
+ "Referer": true,
+ "TE": true,
+ "Trailer": true,
+ "Transfer-Encoding": true,
+ "Upgrade": true,
+ "User-Agent": true,
+ "Via": true
+ };
+ /*jsl:end*/
+
+ function FakeXMLHttpRequest() {
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+ this.requestHeaders = {};
+ this.requestBody = null;
+ this.status = 0;
+ this.statusText = "";
+ this.upload = new UploadProgress();
+ if (sinon.xhr.supportsCORS) {
+ this.withCredentials = false;
+ }
+
+
+ var xhr = this;
+ var events = ["loadstart", "load", "abort", "loadend"];
+
+ function addEventListener(eventName) {
+ xhr.addEventListener(eventName, function (event) {
+ var listener = xhr["on" + eventName];
+
+ if (listener && typeof listener == "function") {
+ listener.call(this, event);
+ }
+ });
+ }
+
+ for (var i = events.length - 1; i >= 0; i--) {
+ addEventListener(events[i]);
+ }
+
+ if (typeof FakeXMLHttpRequest.onCreate == "function") {
+ FakeXMLHttpRequest.onCreate(this);
+ }
+ }
+
+ // An upload object is created for each
+ // FakeXMLHttpRequest and allows upload
+ // events to be simulated using uploadProgress
+ // and uploadError.
+ function UploadProgress() {
+ this.eventListeners = {
+ "progress": [],
+ "load": [],
+ "abort": [],
+ "error": []
+ }
+ }
+
+ UploadProgress.prototype.addEventListener = function(event, listener) {
+ this.eventListeners[event].push(listener);
+ };
+
+ UploadProgress.prototype.removeEventListener = function(event, listener) {
+ var listeners = this.eventListeners[event] || [];
+
+ for (var i = 0, l = listeners.length; i < l; ++i) {
+ if (listeners[i] == listener) {
+ return listeners.splice(i, 1);
+ }
+ }
+ };
+
+ UploadProgress.prototype.dispatchEvent = function(event) {
+ var listeners = this.eventListeners[event.type] || [];
+
+ for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
+ listener(event);
+ }
+ };
+
+ function verifyState(xhr) {
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+
+ if (xhr.sendFlag) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+ }
+
+ // filtering to enable a white-list version of Sinon FakeXhr,
+ // where whitelisted requests are passed through to real XHR
+ function each(collection, callback) {
+ if (!collection) return;
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+ function some(collection, callback) {
+ for (var index = 0; index < collection.length; index++) {
+ if(callback(collection[index]) === true) return true;
+ }
+ return false;
+ }
+ // largest arity in XHR is 5 - XHR#open
+ var apply = function(obj,method,args) {
+ switch(args.length) {
+ case 0: return obj[method]();
+ case 1: return obj[method](args[0]);
+ case 2: return obj[method](args[0],args[1]);
+ case 3: return obj[method](args[0],args[1],args[2]);
+ case 4: return obj[method](args[0],args[1],args[2],args[3]);
+ case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
+ }
+ };
+
+ FakeXMLHttpRequest.filters = [];
+ FakeXMLHttpRequest.addFilter = function(fn) {
+ this.filters.push(fn)
+ };
+ var IE6Re = /MSIE 6/;
+ FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
+ var xhr = new sinon.xhr.workingXHR();
+ each(["open","setRequestHeader","send","abort","getResponseHeader",
+ "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
+ function(method) {
+ fakeXhr[method] = function() {
+ return apply(xhr,method,arguments);
+ };
+ });
+
+ var copyAttrs = function(args) {
+ each(args, function(attr) {
+ try {
+ fakeXhr[attr] = xhr[attr]
+ } catch(e) {
+ if(!IE6Re.test(navigator.userAgent)) throw e;
+ }
+ });
+ };
+
+ var stateChange = function() {
+ fakeXhr.readyState = xhr.readyState;
+ if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ copyAttrs(["status","statusText"]);
+ }
+ if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+ copyAttrs(["responseText"]);
+ }
+ if(xhr.readyState === FakeXMLHttpRequest.DONE) {
+ copyAttrs(["responseXML"]);
+ }
+ if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
+ };
+ if(xhr.addEventListener) {
+ for(var event in fakeXhr.eventListeners) {
+ if(fakeXhr.eventListeners.hasOwnProperty(event)) {
+ each(fakeXhr.eventListeners[event],function(handler) {
+ xhr.addEventListener(event, handler);
+ });
+ }
+ }
+ xhr.addEventListener("readystatechange",stateChange);
+ } else {
+ xhr.onreadystatechange = stateChange;
+ }
+ apply(xhr,"open",xhrArgs);
+ };
+ FakeXMLHttpRequest.useFilters = false;
+
+ function verifyRequestOpened(xhr) {
+ if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
+ }
+ }
+
+ function verifyRequestSent(xhr) {
+ if (xhr.readyState == FakeXMLHttpRequest.DONE) {
+ throw new Error("Request done");
+ }
+ }
+
+ function verifyHeadersReceived(xhr) {
+ if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ throw new Error("No headers received");
+ }
+ }
+
+ function verifyResponseBodyType(body) {
+ if (typeof body != "string") {
+ var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+ body + ", which is not a string.");
+ error.name = "InvalidBodyException";
+ throw error;
+ }
+ }
+
+ sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
+ async: true,
+
+ open: function open(method, url, async, username, password) {
+ this.method = method;
+ this.url = url;
+ this.async = typeof async == "boolean" ? async : true;
+ this.username = username;
+ this.password = password;
+ this.responseText = null;
+ this.responseXML = null;
+ this.requestHeaders = {};
+ this.sendFlag = false;
+ if(sinon.FakeXMLHttpRequest.useFilters === true) {
+ var xhrArgs = arguments;
+ var defake = some(FakeXMLHttpRequest.filters,function(filter) {
+ return filter.apply(this,xhrArgs)
+ });
+ if (defake) {
+ return sinon.FakeXMLHttpRequest.defake(this,arguments);
+ }
+ }
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+ },
+
+ readyStateChange: function readyStateChange(state) {
+ this.readyState = state;
+
+ if (typeof this.onreadystatechange == "function") {
+ try {
+ this.onreadystatechange();
+ } catch (e) {
+ sinon.logError("Fake XHR onreadystatechange handler", e);
+ }
+ }
+
+ this.dispatchEvent(new sinon.Event("readystatechange"));
+
+ switch (this.readyState) {
+ case FakeXMLHttpRequest.DONE:
+ this.dispatchEvent(new sinon.Event("load", false, false, this));
+ this.dispatchEvent(new sinon.Event("loadend", false, false, this));
+ this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
+ if (supportsProgress) {
+ this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
+ }
+ break;
+ }
+ },
+
+ setRequestHeader: function setRequestHeader(header, value) {
+ verifyState(this);
+
+ if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
+ throw new Error("Refused to set unsafe header \"" + header + "\"");
+ }
+
+ if (this.requestHeaders[header]) {
+ this.requestHeaders[header] += "," + value;
+ } else {
+ this.requestHeaders[header] = value;
+ }
+ },
+
+ // Helps testing
+ setResponseHeaders: function setResponseHeaders(headers) {
+ verifyRequestOpened(this);
+ this.responseHeaders = {};
+
+ for (var header in headers) {
+ if (headers.hasOwnProperty(header)) {
+ this.responseHeaders[header] = headers[header];
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+ } else {
+ this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
+ }
+ },
+
+ // Currently treats ALL data as a DOMString (i.e. no Document)
+ send: function send(data) {
+ verifyState(this);
+
+ if (!/^(get|head)$/i.test(this.method)) {
+ if (this.requestHeaders["Content-Type"]) {
+ var value = this.requestHeaders["Content-Type"].split(";");
+ this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
+ } else {
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+ }
+
+ this.requestBody = data;
+ }
+
+ this.errorFlag = false;
+ this.sendFlag = this.async;
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+ if (typeof this.onSend == "function") {
+ this.onSend(this);
+ }
+
+ this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
+ },
+
+ abort: function abort() {
+ this.aborted = true;
+ this.responseText = null;
+ this.errorFlag = true;
+ this.requestHeaders = {};
+
+ if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
+ this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
+ this.sendFlag = false;
+ }
+
+ this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
+
+ this.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+ this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+ if (typeof this.onerror === "function") {
+ this.onerror();
+ }
+ },
+
+ getResponseHeader: function getResponseHeader(header) {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return null;
+ }
+
+ if (/^Set-Cookie2?$/i.test(header)) {
+ return null;
+ }
+
+ header = header.toLowerCase();
+
+ for (var h in this.responseHeaders) {
+ if (h.toLowerCase() == header) {
+ return this.responseHeaders[h];
+ }
+ }
+
+ return null;
+ },
+
+ getAllResponseHeaders: function getAllResponseHeaders() {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return "";
+ }
+
+ var headers = "";
+
+ for (var header in this.responseHeaders) {
+ if (this.responseHeaders.hasOwnProperty(header) &&
+ !/^Set-Cookie2?$/i.test(header)) {
+ headers += header + ": " + this.responseHeaders[header] + "\r\n";
+ }
+ }
+
+ return headers;
+ },
+
+ setResponseBody: function setResponseBody(body) {
+ verifyRequestSent(this);
+ verifyHeadersReceived(this);
+ verifyResponseBodyType(body);
+
+ var chunkSize = this.chunkSize || 10;
+ var index = 0;
+ this.responseText = "";
+
+ do {
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.LOADING);
+ }
+
+ this.responseText += body.substring(index, index + chunkSize);
+ index += chunkSize;
+ } while (index < body.length);
+
+ var type = this.getResponseHeader("Content-Type");
+
+ if (this.responseText &&
+ (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
+ try {
+ this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+ } catch (e) {
+ // Unable to parse XML - no biggie
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ } else {
+ this.readyState = FakeXMLHttpRequest.DONE;
+ }
+ },
+
+ respond: function respond(status, headers, body) {
+ this.status = typeof status == "number" ? status : 200;
+ this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
+ this.setResponseHeaders(headers || {});
+ this.setResponseBody(body || "");
+ },
+
+ uploadProgress: function uploadProgress(progressEventRaw) {
+ if (supportsProgress) {
+ this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
+ }
+ },
+
+ uploadError: function uploadError(error) {
+ if (supportsCustomEvent) {
+ this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
+ }
+ }
+ });
+
+ sinon.extend(FakeXMLHttpRequest, {
+ UNSENT: 0,
+ OPENED: 1,
+ HEADERS_RECEIVED: 2,
+ LOADING: 3,
+ DONE: 4
+ });
+
+ // Borrowed from JSpec
+ FakeXMLHttpRequest.parseXML = function parseXML(text) {
+ var xmlDoc;
+
+ if (typeof DOMParser != "undefined") {
+ var parser = new DOMParser();
+ xmlDoc = parser.parseFromString(text, "text/xml");
+ } else {
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(text);
+ }
+
+ return xmlDoc;
+ };
+
+ FakeXMLHttpRequest.statusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non-Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 300: "Multiple Choice",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 307: "Temporary Redirect",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Request Entity Too Large",
+ 414: "Request-URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Requested Range Not Satisfiable",
+ 417: "Expectation Failed",
+ 422: "Unprocessable Entity",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported"
+ };
+
+ sinon.useFakeXMLHttpRequest = function () {
+ sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+ if (xhr.supportsXHR) {
+ global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
+ }
+
+ if (xhr.supportsActiveX) {
+ global.ActiveXObject = xhr.GlobalActiveXObject;
+ }
+
+ delete sinon.FakeXMLHttpRequest.restore;
+
+ if (keepOnCreate !== true) {
+ delete sinon.FakeXMLHttpRequest.onCreate;
+ }
+ };
+ if (xhr.supportsXHR) {
+ global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
+ }
+
+ if (xhr.supportsActiveX) {
+ global.ActiveXObject = function ActiveXObject(objId) {
+ if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+ return new sinon.FakeXMLHttpRequest();
+ }
+
+ return new xhr.GlobalActiveXObject(objId);
+ };
+ }
+
+ return sinon.FakeXMLHttpRequest;
+ };
+
+ sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
+
+})(typeof global === "object" ? global : this);
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = sinon;
+}
+
+/**
+ * @depend fake_xml_http_request.js
+ */
+/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
+/*global module, require, window*/
+/**
+ * The Sinon "server" mimics a web server that receives requests from
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
+ * both synchronously and asynchronously. To respond synchronously, canned
+ * answers have to be provided upfront.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+sinon.fakeServer = (function () {
+ var push = [].push;
+ function F() {}
+
+ function create(proto) {
+ F.prototype = proto;
+ return new F();
+ }
+
+ function responseArray(handler) {
+ var response = handler;
+
+ if (Object.prototype.toString.call(handler) != "[object Array]") {
+ response = [200, {}, handler];
+ }
+
+ if (typeof response[2] != "string") {
+ throw new TypeError("Fake server response body should be string, but was " +
+ typeof response[2]);
+ }
+
+ return response;
+ }
+
+ var wloc = typeof window !== "undefined" ? window.location : {};
+ var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+ function matchOne(response, reqMethod, reqUrl) {
+ var rmeth = response.method;
+ var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
+ var url = response.url;
+ var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
+
+ return matchMethod && matchUrl;
+ }
+
+ function match(response, request) {
+ var requestUrl = request.url;
+
+ if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+ requestUrl = requestUrl.replace(rCurrLoc, "");
+ }
+
+ if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+ if (typeof response.response == "function") {
+ var ru = response.url;
+ var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
+ return response.response.apply(response, args);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ function log(response, request) {
+ var str;
+
+ str = "Request:\n" + sinon.format(request) + "\n\n";
+ str += "Response:\n" + sinon.format(response) + "\n\n";
+
+ sinon.log(str);
+ }
+
+ return {
+ create: function () {
+ var server = create(this);
+ this.xhr = sinon.useFakeXMLHttpRequest();
+ server.requests = [];
+
+ this.xhr.onCreate = function (xhrObj) {
+ server.addRequest(xhrObj);
+ };
+
+ return server;
+ },
+
+ addRequest: function addRequest(xhrObj) {
+ var server = this;
+ push.call(this.requests, xhrObj);
+
+ xhrObj.onSend = function () {
+ server.handleRequest(this);
+
+ if (server.autoRespond && !server.responding) {
+ setTimeout(function () {
+ server.responding = false;
+ server.respond();
+ }, server.autoRespondAfter || 10);
+
+ server.responding = true;
+ }
+ };
+ },
+
+ getHTTPMethod: function getHTTPMethod(request) {
+ if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+ var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+ return !!matches ? matches[1] : request.method;
+ }
+
+ return request.method;
+ },
+
+ handleRequest: function handleRequest(xhr) {
+ if (xhr.async) {
+ if (!this.queue) {
+ this.queue = [];
+ }
+
+ push.call(this.queue, xhr);
+ } else {
+ this.processRequest(xhr);
+ }
+ },
+
+ respondWith: function respondWith(method, url, body) {
+ if (arguments.length == 1 && typeof method != "function") {
+ this.response = responseArray(method);
+ return;
+ }
+
+ if (!this.responses) { this.responses = []; }
+
+ if (arguments.length == 1) {
+ body = method;
+ url = method = null;
+ }
+
+ if (arguments.length == 2) {
+ body = url;
+ url = method;
+ method = null;
+ }
+
+ push.call(this.responses, {
+ method: method,
+ url: url,
+ response: typeof body == "function" ? body : responseArray(body)
+ });
+ },
+
+ respond: function respond() {
+ if (arguments.length > 0) this.respondWith.apply(this, arguments);
+ var queue = this.queue || [];
+ var requests = queue.splice(0);
+ var request;
+
+ while(request = requests.shift()) {
+ this.processRequest(request);
+ }
+ },
+
+ processRequest: function processRequest(request) {
+ try {
+ if (request.aborted) {
+ return;
+ }
+
+ var response = this.response || [404, {}, ""];
+
+ if (this.responses) {
+ for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
+ if (match.call(this, this.responses[i], request)) {
+ response = this.responses[i].response;
+ break;
+ }
+ }
+ }
+
+ if (request.readyState != 4) {
+ log(response, request);
+
+ request.respond(response[0], response[1], response[2]);
+ }
+ } catch (e) {
+ sinon.logError("Fake server request processing", e);
+ }
+ },
+
+ restore: function restore() {
+ return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+ }
+ };
+}());
+
+if (typeof module !== 'undefined' && module.exports) {
+ module.exports = sinon;
+}
+
+/**
+ * @depend fake_server.js
+ * @depend fake_timers.js
+ */
+/*jslint browser: true, eqeqeq: false, onevar: false*/
+/*global sinon*/
+/**
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
+ * it polls the object for completion with setInterval. Dispite the direct
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
+ * in any environment where the ajax implementation depends on setInterval or
+ * setTimeout.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function () {
+ function Server() {}
+ Server.prototype = sinon.fakeServer;
+
+ sinon.fakeServerWithClock = new Server();
+
+ sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
+ if (xhr.async) {
+ if (typeof setTimeout.clock == "object") {
+ this.clock = setTimeout.clock;
+ } else {
+ this.clock = sinon.useFakeTimers();
+ this.resetClock = true;
+ }
+
+ if (!this.longestTimeout) {
+ var clockSetTimeout = this.clock.setTimeout;
+ var clockSetInterval = this.clock.setInterval;
+ var server = this;
+
+ this.clock.setTimeout = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetTimeout.apply(this, arguments);
+ };
+
+ this.clock.setInterval = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetInterval.apply(this, arguments);
+ };
+ }
+ }
+
+ return sinon.fakeServer.addRequest.call(this, xhr);
+ };
+
+ sinon.fakeServerWithClock.respond = function respond() {
+ var returnVal = sinon.fakeServer.respond.apply(this, arguments);
+
+ if (this.clock) {
+ this.clock.tick(this.longestTimeout || 0);
+ this.longestTimeout = 0;
+
+ if (this.resetClock) {
+ this.clock.restore();
+ this.resetClock = false;
+ }
+ }
+
+ return returnVal;
+ };
+
+ sinon.fakeServerWithClock.restore = function restore() {
+ if (this.clock) {
+ this.clock.restore();
+ }
+
+ return sinon.fakeServer.restore.apply(this, arguments);
+ };
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend collection.js
+ * @depend util/fake_timers.js
+ * @depend util/fake_server_with_clock.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global require, module*/
+/**
+ * Manages fake collections as well as fake utilities such as Sinon's
+ * timers and fake XHR implementation in one convenient object.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof module !== 'undefined' && module.exports) {
+ var sinon = require("../sinon");
+ sinon.extend(sinon, require("./util/fake_timers"));
+}
+
+(function () {
+ var push = [].push;
+
+ function exposeValue(sandbox, config, key, value) {
+ if (!value) {
+ return;
+ }
+
+ if (config.injectInto && !(key in config.injectInto)) {
+ config.injectInto[key] = value;
+ sandbox.injectedKeys.push(key);
+ } else {
+ push.call(sandbox.args, value);
+ }
+ }
+
+ function prepareSandboxFromConfig(config) {
+ var sandbox = sinon.create(sinon.sandbox);
+
+ if (config.useFakeServer) {
+ if (typeof config.useFakeServer == "object") {
+ sandbox.serverPrototype = config.useFakeServer;
+ }
+
+ sandbox.useFakeServer();
+ }
+
+ if (config.useFakeTimers) {
+ if (typeof config.useFakeTimers == "object") {
+ sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+ } else {
+ sandbox.useFakeTimers();
+ }
+ }
+
+ return sandbox;
+ }
+
+ sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
+ useFakeTimers: function useFakeTimers() {
+ this.clock = sinon.useFakeTimers.apply(sinon, arguments);
+
+ return this.add(this.clock);
+ },
+
+ serverPrototype: sinon.fakeServer,
+
+ useFakeServer: function useFakeServer() {
+ var proto = this.serverPrototype || sinon.fakeServer;
+
+ if (!proto || !proto.create) {
+ return null;
+ }
+
+ this.server = proto.create();
+ return this.add(this.server);
+ },
+
+ inject: function (obj) {
+ sinon.collection.inject.call(this, obj);
+
+ if (this.clock) {
+ obj.clock = this.clock;
+ }
+
+ if (this.server) {
+ obj.server = this.server;
+ obj.requests = this.server.requests;
+ }
+
+ return obj;
+ },
+
+ restore: function () {
+ sinon.collection.restore.apply(this, arguments);
+ this.restoreContext();
+ },
+
+ restoreContext: function () {
+ if (this.injectedKeys) {
+ for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
+ delete this.injectInto[this.injectedKeys[i]];
+ }
+ this.injectedKeys = [];
+ }
+ },
+
+ create: function (config) {
+ if (!config) {
+ return sinon.create(sinon.sandbox);
+ }
+
+ var sandbox = prepareSandboxFromConfig(config);
+ sandbox.args = sandbox.args || [];
+ sandbox.injectedKeys = [];
+ sandbox.injectInto = config.injectInto;
+ var prop, value, exposed = sandbox.inject({});
+
+ if (config.properties) {
+ for (var i = 0, l = config.properties.length; i < l; i++) {
+ prop = config.properties[i];
+ value = exposed[prop] || prop == "sandbox" && sandbox;
+ exposeValue(sandbox, config, prop, value);
+ }
+ } else {
+ exposeValue(sandbox, config, "sandbox", value);
+ }
+
+ return sandbox;
+ }
+ });
+
+ sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
+
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = sinon.sandbox;
+ }
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ * @depend sandbox.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Test function, sandboxes fakes
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function test(callback) {
+ var type = typeof callback;
+
+ if (type != "function") {
+ throw new TypeError("sinon.test needs to wrap a test function, got " + type);
+ }
+
+ return function () {
+ var config = sinon.getConfig(sinon.config);
+ config.injectInto = config.injectIntoThis && this || config.injectInto;
+ var sandbox = sinon.sandbox.create(config);
+ var exception, result;
+ var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
+
+ try {
+ result = callback.apply(this, args);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (typeof exception !== "undefined") {
+ sandbox.restore();
+ throw exception;
+ }
+ else {
+ sandbox.verifyAndRestore();
+ }
+
+ return result;
+ };
+ }
+
+ test.config = {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ };
+
+ if (commonJSModule) {
+ module.exports = test;
+ } else {
+ sinon.test = test;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend test.js
+ */
+/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
+/*global module, require, sinon*/
+/**
+ * Test case, sandboxes all test functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon || !Object.prototype.hasOwnProperty) {
+ return;
+ }
+
+ function createTest(property, setUp, tearDown) {
+ return function () {
+ if (setUp) {
+ setUp.apply(this, arguments);
+ }
+
+ var exception, result;
+
+ try {
+ result = property.apply(this, arguments);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (tearDown) {
+ tearDown.apply(this, arguments);
+ }
+
+ if (exception) {
+ throw exception;
+ }
+
+ return result;
+ };
+ }
+
+ function testCase(tests, prefix) {
+ /*jsl:ignore*/
+ if (!tests || typeof tests != "object") {
+ throw new TypeError("sinon.testCase needs an object with test functions");
+ }
+ /*jsl:end*/
+
+ prefix = prefix || "test";
+ var rPrefix = new RegExp("^" + prefix);
+ var methods = {}, testName, property, method;
+ var setUp = tests.setUp;
+ var tearDown = tests.tearDown;
+
+ for (testName in tests) {
+ if (tests.hasOwnProperty(testName)) {
+ property = tests[testName];
+
+ if (/^(setUp|tearDown)$/.test(testName)) {
+ continue;
+ }
+
+ if (typeof property == "function" && rPrefix.test(testName)) {
+ method = property;
+
+ if (setUp || tearDown) {
+ method = createTest(property, setUp, tearDown);
+ }
+
+ methods[testName] = sinon.test(method);
+ } else {
+ methods[testName] = tests[testName];
+ }
+ }
+ }
+
+ return methods;
+ }
+
+ if (commonJSModule) {
+ module.exports = testCase;
+ } else {
+ sinon.testCase = testCase;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Assertions matching the test spy retrieval interface.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon, global) {
+ var commonJSModule = typeof module !== "undefined" && module.exports;
+ var slice = Array.prototype.slice;
+ var assert;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function verifyIsStub() {
+ var method;
+
+ for (var i = 0, l = arguments.length; i < l; ++i) {
+ method = arguments[i];
+
+ if (!method) {
+ assert.fail("fake is not a spy");
+ }
+
+ if (typeof method != "function") {
+ assert.fail(method + " is not a function");
+ }
+
+ if (typeof method.getCall != "function") {
+ assert.fail(method + " is not stubbed");
+ }
+ }
+ }
+
+ function failAssertion(object, msg) {
+ object = object || global;
+ var failMethod = object.fail || assert.fail;
+ failMethod.call(object, msg);
+ }
+
+ function mirrorPropAsAssertion(name, method, message) {
+ if (arguments.length == 2) {
+ message = method;
+ method = name;
+ }
+
+ assert[name] = function (fake) {
+ verifyIsStub(fake);
+
+ var args = slice.call(arguments, 1);
+ var failed = false;
+
+ if (typeof method == "function") {
+ failed = !method(fake);
+ } else {
+ failed = typeof fake[method] == "function" ?
+ !fake[method].apply(fake, args) : !fake[method];
+ }
+
+ if (failed) {
+ failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
+ } else {
+ assert.pass(name);
+ }
+ };
+ }
+
+ function exposedName(prefix, prop) {
+ return !prefix || /^fail/.test(prop) ? prop :
+ prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+ }
+
+ assert = {
+ failException: "AssertError",
+
+ fail: function fail(message) {
+ var error = new Error(message);
+ error.name = this.failException || assert.failException;
+
+ throw error;
+ },
+
+ pass: function pass(assertion) {},
+
+ callOrder: function assertCallOrder() {
+ verifyIsStub.apply(null, arguments);
+ var expected = "", actual = "";
+
+ if (!sinon.calledInOrder(arguments)) {
+ try {
+ expected = [].join.call(arguments, ", ");
+ var calls = slice.call(arguments);
+ var i = calls.length;
+ while (i) {
+ if (!calls[--i].called) {
+ calls.splice(i, 1);
+ }
+ }
+ actual = sinon.orderByFirstCall(calls).join(", ");
+ } catch (e) {
+ // If this fails, we'll just fall back to the blank string
+ }
+
+ failAssertion(this, "expected " + expected + " to be " +
+ "called in order but were called as " + actual);
+ } else {
+ assert.pass("callOrder");
+ }
+ },
+
+ callCount: function assertCallCount(method, count) {
+ verifyIsStub(method);
+
+ if (method.callCount != count) {
+ var msg = "expected %n to be called " + sinon.timesInWords(count) +
+ " but was called %c%C";
+ failAssertion(this, method.printf(msg));
+ } else {
+ assert.pass("callCount");
+ }
+ },
+
+ expose: function expose(target, options) {
+ if (!target) {
+ throw new TypeError("target is null or undefined");
+ }
+
+ var o = options || {};
+ var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
+ var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
+
+ for (var method in this) {
+ if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
+ target[exposedName(prefix, method)] = this[method];
+ }
+ }
+
+ return target;
+ },
+
+ match: function match(actual, expectation) {
+ var matcher = sinon.match(expectation);
+ if (matcher.test(actual)) {
+ assert.pass("match");
+ } else {
+ var formatted = [
+ "expected value to match",
+ " expected = " + sinon.format(expectation),
+ " actual = " + sinon.format(actual)
+ ]
+ failAssertion(this, formatted.join("\n"));
+ }
+ }
+ };
+
+ mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+ mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
+ "expected %n to not have been called but was called %c%C");
+ mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+ mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+ mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+ mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
+ mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
+ mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
+ mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
+ mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
+ mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
+ mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+ mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+ if (commonJSModule) {
+ module.exports = assert;
+ } else {
+ sinon.assert = assert;
+ }
+}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
+
+return sinon;}.call(typeof window != 'undefined' && window || {}));
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/meteor/assets.js b/wms/contract-repair/semantic/test/meteor/assets.js
new file mode 100644
index 00000000..40f4b40e
--- /dev/null
+++ b/wms/contract-repair/semantic/test/meteor/assets.js
@@ -0,0 +1,20 @@
+var assets = [
+ 'dist/themes/default/assets/images/flags.png',
+];
+
+// Check that the font files are downloadable. Meteor places assets at /packages/
/.
+assets.forEach(function (path) {
+ Tinytest.addAsync('image ' + path + ' is shipped', function (test, done) {
+ HTTP.get('/packages/semantic_ui/' + path, function callback(error, result) {
+ if (error) {
+ test.fail({message: 'Image failed to load'});
+ }
+ else {
+ test.isTrue(result.content.length > 10000, 'Image ' + path + ' could not be downloaded');
+ }
+ done();
+ });
+ });
+});
+
+
diff --git a/wms/contract-repair/semantic/test/meteor/fonts.js b/wms/contract-repair/semantic/test/meteor/fonts.js
new file mode 100644
index 00000000..195d5159
--- /dev/null
+++ b/wms/contract-repair/semantic/test/meteor/fonts.js
@@ -0,0 +1,16 @@
+// Check that the font files are downloadable. Meteor places assets at /packages//.
+['eot', 'otf', 'svg', 'ttf', 'woff']
+ .forEach(function (extension) {
+ Tinytest.addAsync(extension + ' fonts are shipped', function (test, done) {
+ HTTP.get('/packages/semantic_ui/dist/themes/default/assets/fonts/icons.' + extension, function callback(error, result) {
+ if (error) {
+ test.fail({message: 'Font failed to load'});
+ }
+ else {
+ test.isTrue(result.content.length > 10000, extension + ' font could not be downloaded');
+ }
+ done();
+ });
+ });
+ })
+;
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/accordion.spec.js b/wms/contract-repair/semantic/test/modules/accordion.spec.js
new file mode 100644
index 00000000..dde2b277
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/accordion.spec.js
@@ -0,0 +1,10 @@
+describe("UI Accordion", function() {
+
+ $.fn.dimmer.settings.debug = false;
+
+ moduleTests({
+ module : 'accordion',
+ element : '.ui.accordion'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/checkbox.spec.js b/wms/contract-repair/semantic/test/modules/checkbox.spec.js
new file mode 100644
index 00000000..5c10bf22
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/checkbox.spec.js
@@ -0,0 +1,8 @@
+describe("UI Checkbox", function() {
+
+ moduleTests({
+ module : 'checkbox',
+ element : '.ui.checkbox'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/dropdown.spec.js b/wms/contract-repair/semantic/test/modules/dropdown.spec.js
new file mode 100644
index 00000000..87c13cf3
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/dropdown.spec.js
@@ -0,0 +1,8 @@
+describe("UI Dropdown", function() {
+
+ moduleTests({
+ module : 'dropdown',
+ element : '.ui.dropdown'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/modal.spec.js b/wms/contract-repair/semantic/test/modules/modal.spec.js
new file mode 100644
index 00000000..f9322feb
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/modal.spec.js
@@ -0,0 +1,10 @@
+describe("UI Modal", function() {
+
+ $.fn.dimmer.settings.debug = false;
+
+ moduleTests({
+ module : 'modal',
+ element : '.ui.modal'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/module.spec.js b/wms/contract-repair/semantic/test/modules/module.spec.js
new file mode 100644
index 00000000..ff26c528
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/module.spec.js
@@ -0,0 +1,218 @@
+
+function moduleTests(ui) {
+ var
+ module = ui.module,
+ element = ui.element,
+ singleton = ui.singleton,
+ name = $.fn[module].settings.name,
+
+ testValue = 'Test',
+ fixtures = jasmine.getFixtures(),
+
+ originalSettings,
+ $modules,
+ $oneModule,
+ $module,
+ $clone
+ ;
+
+ // set fixture path
+ fixtures.fixturesPath = 'base/test/fixtures/';
+
+ // disable debug
+ $.fn[module].settings.debug = false;
+ $.fn[module].settings.performance = false;
+ $.fn[module].settings.verbose = false;
+
+
+ beforeEach(function() {
+ // load fixtures
+ fixtures.load(module + '.html');
+ // save settings
+ originalSettings = $.fn[module].settings;
+
+ // module available in scope
+ $module = $(element);
+
+ // one module available in fixture
+ if($module.size() == 1) {
+ $oneModule = $module;
+ $clone = $module.clone().appendTo( $(sandbox()) );
+ $modules = $clone.add($module);
+ }
+ // multiple modules available in fixture
+ else {
+ $modules = $(element);
+ $clone = $module.eq(1);
+ $oneModule = $modules.first();
+ }
+
+ });
+
+ afterEach(function() {
+ // restore settings
+ $.fn[module].settings = originalSettings;
+ // remove element
+ $(element).remove();
+ });
+
+ /*******************************
+ Module
+ *******************************/
+
+ /*-------------------
+ Instantiation
+ --------------------*/
+ describe('Module', function() {
+
+ it("allows chaining when no settings returned", function() {
+ var $chain = $modules[module]();
+ expect($chain).toExist();
+ expect($chain.size()).toBe($modules.size());
+ });
+
+ it("returns a string when one setting returned", function() {
+ var result = $oneModule[module]('setting', 'name');
+ expect(typeof result).toBe('string');
+ });
+
+ it("returns an array when multiple settings returned", function() {
+ var result = $modules[module]('setting', 'name');
+ expect( $.isArray(result) ).toBeTruthy();
+ });
+
+ it("has an instance in metadata after init", function() {
+ $oneModule[module]();
+ expect($module).toHaveData('module-' + module);
+ });
+
+ });
+
+ /*-------------------
+ Settings
+ --------------------*/
+
+ describe('Settings', function() {
+
+ it("clears settings on re-init", function() {
+ $oneModule[module]({
+ name: testValue
+ });
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+ expect(retrievedValue).toBe(testValue);
+
+ // reinit
+ $oneModule[module]();
+ retrievedValue = $oneModule[module]('setting', 'name');
+ expect(retrievedValue).toBe(name);
+ });
+
+ it("allows default settings to be changed", function() {
+ $.fn[module].settings.name = testValue;
+ $oneModule[module]();
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+ $.fn[module].settings.name = name;
+
+ expect(retrievedValue).toBe(testValue);
+ });
+
+ it("allows settings to be changed during init", function() {
+ $oneModule[module]({
+ name: testValue
+ });
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+
+ expect(retrievedValue).toBe(testValue);
+ });
+
+ it("allows settings to be changed during runtime", function() {
+ $oneModule[module]();
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+
+ expect(retrievedValue).toBe(name);
+ });
+
+ });
+
+ /*-------------------
+ Groups
+ --------------------*/
+
+ if(!singleton) {
+
+ describe('Group Contamination', function() {
+
+ it("creates settings for all instances", function() {
+ $modules[module]('setting', 'name', testValue);
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+ var clonedSetting = $clone[module]('setting', 'name');
+
+ expect(retrievedValue).toBe(testValue);
+ expect(clonedSetting).toBe(testValue);
+
+ $oneModule[module]({
+ 'name': testValue
+ });
+
+ expect(retrievedValue).toBe(testValue);
+ expect(clonedSetting).toBe(testValue);
+
+ });
+
+ it("does not change other elements settings when changing one element", function() {
+ $modules[module]();
+ $oneModule[module]('setting', 'name', testValue);
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+ var clonedSetting = $clone[module]('setting', 'name');
+
+ expect(retrievedValue).toBe(testValue);
+ expect(clonedSetting).toBe(name);
+
+ });
+
+ it("does not change other elements when re-initialized", function() {
+ $modules[module]();
+
+ $oneModule[module]({
+ 'name': testValue
+ });
+
+ var retrievedValue = $oneModule[module]('setting', 'name');
+ var clonedSetting = $clone[module]('setting', 'name');
+
+ expect(retrievedValue).toBe(testValue);
+ expect(clonedSetting).toBe(name);
+
+ });
+
+ });
+
+ }
+
+ /*-------------------
+ Destroy
+ --------------------*/
+ describe('Destroy', function() {
+
+ it("removes all events from page", function() {
+ $module[module]('destroy');
+ if($.events().length > 0) {
+ dump($.events());
+ }
+ expect($.events().length).toBe(0);
+ });
+
+ it("removes instance metadata", function() {
+ $module[module]('destroy');
+ expect( $module.data('module-'+ module) ).toBe(undefined);
+ });
+
+ });
+
+}
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/popup.spec.js b/wms/contract-repair/semantic/test/modules/popup.spec.js
new file mode 100644
index 00000000..952cee8e
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/popup.spec.js
@@ -0,0 +1,8 @@
+xdescribe("UI Popup", function() {
+
+ moduleTests({
+ module : 'popup',
+ element : 'i.icon'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/search.spec.js b/wms/contract-repair/semantic/test/modules/search.spec.js
new file mode 100644
index 00000000..5dd8576d
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/search.spec.js
@@ -0,0 +1,8 @@
+xdescribe("UI Search", function() {
+
+ moduleTests({
+ module : 'search',
+ element : '.ui.search'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/shape.spec.js b/wms/contract-repair/semantic/test/modules/shape.spec.js
new file mode 100644
index 00000000..c0f284f3
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/shape.spec.js
@@ -0,0 +1,8 @@
+describe("UI Shape", function() {
+
+ moduleTests({
+ module : 'shape',
+ element : '.ui.shape'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/sidebar.spec.js b/wms/contract-repair/semantic/test/modules/sidebar.spec.js
new file mode 100644
index 00000000..6ae09baa
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/sidebar.spec.js
@@ -0,0 +1,8 @@
+describe("UI Rating", function() {
+
+ moduleTests({
+ module : 'rating',
+ element : '.ui.rating'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/tab.spec.js b/wms/contract-repair/semantic/test/modules/tab.spec.js
new file mode 100644
index 00000000..0a22ad59
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/tab.spec.js
@@ -0,0 +1,9 @@
+xdescribe("UI Tab", function() {
+
+ moduleTests({
+ module : 'tab',
+ element : '.ui.menu .item',
+ singleton : true
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/transition.spec.js b/wms/contract-repair/semantic/test/modules/transition.spec.js
new file mode 100644
index 00000000..ebfe8fc5
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/transition.spec.js
@@ -0,0 +1,8 @@
+xdescribe("UI Transition", function() {
+
+ moduleTests({
+ module : 'transition',
+ element : '.ui.image'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/semantic/test/modules/video.spec.js b/wms/contract-repair/semantic/test/modules/video.spec.js
new file mode 100644
index 00000000..23ad8aca
--- /dev/null
+++ b/wms/contract-repair/semantic/test/modules/video.spec.js
@@ -0,0 +1,8 @@
+describe("UI Video", function() {
+
+ moduleTests({
+ module : 'video',
+ element : '.ui.video'
+ });
+
+});
\ No newline at end of file
diff --git a/wms/contract-repair/styles/BiauKai.ttf b/wms/contract-repair/styles/BiauKai.ttf
new file mode 100644
index 00000000..e59484ab
Binary files /dev/null and b/wms/contract-repair/styles/BiauKai.ttf differ
diff --git a/wms/contract-repair/styles/font-awesome/all.min.css b/wms/contract-repair/styles/font-awesome/all.min.css
new file mode 100644
index 00000000..d949e4f2
--- /dev/null
+++ b/wms/contract-repair/styles/font-awesome/all.min.css
@@ -0,0 +1,9 @@
+/*!
+ * Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ * Copyright 2023 Fonticons, Inc.
+ */
+.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-classic,.fa-regular,.fa-sharp,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{-webkit-animation-name:fa-beat;animation-name:fa-beat;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{-webkit-animation-name:fa-bounce;animation-name:fa-bounce;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{-webkit-animation-name:fa-fade;animation-name:fa-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{-webkit-animation-name:fa-beat-fade;animation-name:fa-beat-fade;-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1));animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{-webkit-animation-name:fa-flip;animation-name:fa-flip;-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,ease-in-out);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{-webkit-animation-name:fa-shake;animation-name:fa-shake;-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{-webkit-animation-delay:var(--fa-animation-delay,0s);animation-delay:var(--fa-animation-delay,0s);-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-duration:var(--fa-animation-duration,2s);animation-duration:var(--fa-animation-duration,2s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,linear);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{-webkit-animation-name:fa-spin;animation-name:fa-spin;-webkit-animation-direction:var(--fa-animation-direction,normal);animation-direction:var(--fa-animation-direction,normal);-webkit-animation-duration:var(--fa-animation-duration,1s);animation-duration:var(--fa-animation-duration,1s);-webkit-animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-iteration-count:var(--fa-animation-iteration-count,infinite);-webkit-animation-timing-function:var(--fa-animation-timing,steps(8));animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{-webkit-animation-delay:-1ms;animation-delay:-1ms;-webkit-animation-duration:1ms;animation-duration:1ms;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-duration:0s;transition-duration:0s}}@-webkit-keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-beat{0%,90%{-webkit-transform:scale(1);transform:scale(1)}45%{-webkit-transform:scale(var(--fa-beat-scale,1.25));transform:scale(var(--fa-beat-scale,1.25))}}@-webkit-keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@keyframes fa-bounce{0%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}10%{-webkit-transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0);transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{-webkit-transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em));transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{-webkit-transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0);transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{-webkit-transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em));transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}to{-webkit-transform:scale(1) translateY(0);transform:scale(1) translateY(0)}}@-webkit-keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@-webkit-keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);-webkit-transform:scale(1);transform:scale(1)}50%{opacity:1;-webkit-transform:scale(var(--fa-beat-fade-scale,1.125));transform:scale(var(--fa-beat-fade-scale,1.125))}}@-webkit-keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-flip{50%{-webkit-transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg));transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@-webkit-keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes fa-shake{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}4%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}8%,24%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}12%,28%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}20%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}32%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}36%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}40%,to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}.fa-rotate-by{-webkit-transform:rotate(var(--fa-rotate-angle,none));transform:rotate(var(--fa-rotate-angle,none))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)}
+
+.fa-0:before{content:"\30"}.fa-1:before{content:"\31"}.fa-2:before{content:"\32"}.fa-3:before{content:"\33"}.fa-4:before{content:"\34"}.fa-5:before{content:"\35"}.fa-6:before{content:"\36"}.fa-7:before{content:"\37"}.fa-8:before{content:"\38"}.fa-9:before{content:"\39"}.fa-fill-drip:before{content:"\f576"}.fa-arrows-to-circle:before{content:"\e4bd"}.fa-chevron-circle-right:before,.fa-circle-chevron-right:before{content:"\f138"}.fa-at:before{content:"\40"}.fa-trash-alt:before,.fa-trash-can:before{content:"\f2ed"}.fa-text-height:before{content:"\f034"}.fa-user-times:before,.fa-user-xmark:before{content:"\f235"}.fa-stethoscope:before{content:"\f0f1"}.fa-comment-alt:before,.fa-message:before{content:"\f27a"}.fa-info:before{content:"\f129"}.fa-compress-alt:before,.fa-down-left-and-up-right-to-center:before{content:"\f422"}.fa-explosion:before{content:"\e4e9"}.fa-file-alt:before,.fa-file-lines:before,.fa-file-text:before{content:"\f15c"}.fa-wave-square:before{content:"\f83e"}.fa-ring:before{content:"\f70b"}.fa-building-un:before{content:"\e4d9"}.fa-dice-three:before{content:"\f527"}.fa-calendar-alt:before,.fa-calendar-days:before{content:"\f073"}.fa-anchor-circle-check:before{content:"\e4aa"}.fa-building-circle-arrow-right:before{content:"\e4d1"}.fa-volleyball-ball:before,.fa-volleyball:before{content:"\f45f"}.fa-arrows-up-to-line:before{content:"\e4c2"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-circle-minus:before,.fa-minus-circle:before{content:"\f056"}.fa-door-open:before{content:"\f52b"}.fa-right-from-bracket:before,.fa-sign-out-alt:before{content:"\f2f5"}.fa-atom:before{content:"\f5d2"}.fa-soap:before{content:"\e06e"}.fa-heart-music-camera-bolt:before,.fa-icons:before{content:"\f86d"}.fa-microphone-alt-slash:before,.fa-microphone-lines-slash:before{content:"\f539"}.fa-bridge-circle-check:before{content:"\e4c9"}.fa-pump-medical:before{content:"\e06a"}.fa-fingerprint:before{content:"\f577"}.fa-hand-point-right:before{content:"\f0a4"}.fa-magnifying-glass-location:before,.fa-search-location:before{content:"\f689"}.fa-forward-step:before,.fa-step-forward:before{content:"\f051"}.fa-face-smile-beam:before,.fa-smile-beam:before{content:"\f5b8"}.fa-flag-checkered:before{content:"\f11e"}.fa-football-ball:before,.fa-football:before{content:"\f44e"}.fa-school-circle-exclamation:before{content:"\e56c"}.fa-crop:before{content:"\f125"}.fa-angle-double-down:before,.fa-angles-down:before{content:"\f103"}.fa-users-rectangle:before{content:"\e594"}.fa-people-roof:before{content:"\e537"}.fa-people-line:before{content:"\e534"}.fa-beer-mug-empty:before,.fa-beer:before{content:"\f0fc"}.fa-diagram-predecessor:before{content:"\e477"}.fa-arrow-up-long:before,.fa-long-arrow-up:before{content:"\f176"}.fa-burn:before,.fa-fire-flame-simple:before{content:"\f46a"}.fa-male:before,.fa-person:before{content:"\f183"}.fa-laptop:before{content:"\f109"}.fa-file-csv:before{content:"\f6dd"}.fa-menorah:before{content:"\f676"}.fa-truck-plane:before{content:"\e58f"}.fa-record-vinyl:before{content:"\f8d9"}.fa-face-grin-stars:before,.fa-grin-stars:before{content:"\f587"}.fa-bong:before{content:"\f55c"}.fa-pastafarianism:before,.fa-spaghetti-monster-flying:before{content:"\f67b"}.fa-arrow-down-up-across-line:before{content:"\e4af"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f2e5"}.fa-jar-wheat:before{content:"\e517"}.fa-envelopes-bulk:before,.fa-mail-bulk:before{content:"\f674"}.fa-file-circle-exclamation:before{content:"\e4eb"}.fa-circle-h:before,.fa-hospital-symbol:before{content:"\f47e"}.fa-pager:before{content:"\f815"}.fa-address-book:before,.fa-contact-book:before{content:"\f2b9"}.fa-strikethrough:before{content:"\f0cc"}.fa-k:before{content:"\4b"}.fa-landmark-flag:before{content:"\e51c"}.fa-pencil-alt:before,.fa-pencil:before{content:"\f303"}.fa-backward:before{content:"\f04a"}.fa-caret-right:before{content:"\f0da"}.fa-comments:before{content:"\f086"}.fa-file-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-code-pull-request:before{content:"\e13c"}.fa-clipboard-list:before{content:"\f46d"}.fa-truck-loading:before,.fa-truck-ramp-box:before{content:"\f4de"}.fa-user-check:before{content:"\f4fc"}.fa-vial-virus:before{content:"\e597"}.fa-sheet-plastic:before{content:"\e571"}.fa-blog:before{content:"\f781"}.fa-user-ninja:before{content:"\f504"}.fa-person-arrow-up-from-line:before{content:"\e539"}.fa-scroll-torah:before,.fa-torah:before{content:"\f6a0"}.fa-broom-ball:before,.fa-quidditch-broom-ball:before,.fa-quidditch:before{content:"\f458"}.fa-toggle-off:before{content:"\f204"}.fa-archive:before,.fa-box-archive:before{content:"\f187"}.fa-person-drowning:before{content:"\e545"}.fa-arrow-down-9-1:before,.fa-sort-numeric-desc:before,.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-face-grin-tongue-squint:before,.fa-grin-tongue-squint:before{content:"\f58a"}.fa-spray-can:before{content:"\f5bd"}.fa-truck-monster:before{content:"\f63b"}.fa-w:before{content:"\57"}.fa-earth-africa:before,.fa-globe-africa:before{content:"\f57c"}.fa-rainbow:before{content:"\f75b"}.fa-circle-notch:before{content:"\f1ce"}.fa-tablet-alt:before,.fa-tablet-screen-button:before{content:"\f3fa"}.fa-paw:before{content:"\f1b0"}.fa-cloud:before{content:"\f0c2"}.fa-trowel-bricks:before{content:"\e58a"}.fa-face-flushed:before,.fa-flushed:before{content:"\f579"}.fa-hospital-user:before{content:"\f80d"}.fa-tent-arrow-left-right:before{content:"\e57f"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-binoculars:before{content:"\f1e5"}.fa-microphone-slash:before{content:"\f131"}.fa-box-tissue:before{content:"\e05b"}.fa-motorcycle:before{content:"\f21c"}.fa-bell-concierge:before,.fa-concierge-bell:before{content:"\f562"}.fa-pen-ruler:before,.fa-pencil-ruler:before{content:"\f5ae"}.fa-people-arrows-left-right:before,.fa-people-arrows:before{content:"\e068"}.fa-mars-and-venus-burst:before{content:"\e523"}.fa-caret-square-right:before,.fa-square-caret-right:before{content:"\f152"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-sun-plant-wilt:before{content:"\e57a"}.fa-toilets-portable:before{content:"\e584"}.fa-hockey-puck:before{content:"\f453"}.fa-table:before{content:"\f0ce"}.fa-magnifying-glass-arrow-right:before{content:"\e521"}.fa-digital-tachograph:before,.fa-tachograph-digital:before{content:"\f566"}.fa-users-slash:before{content:"\e073"}.fa-clover:before{content:"\e139"}.fa-mail-reply:before,.fa-reply:before{content:"\f3e5"}.fa-star-and-crescent:before{content:"\f699"}.fa-house-fire:before{content:"\e50c"}.fa-minus-square:before,.fa-square-minus:before{content:"\f146"}.fa-helicopter:before{content:"\f533"}.fa-compass:before{content:"\f14e"}.fa-caret-square-down:before,.fa-square-caret-down:before{content:"\f150"}.fa-file-circle-question:before{content:"\e4ef"}.fa-laptop-code:before{content:"\f5fc"}.fa-swatchbook:before{content:"\f5c3"}.fa-prescription-bottle:before{content:"\f485"}.fa-bars:before,.fa-navicon:before{content:"\f0c9"}.fa-people-group:before{content:"\e533"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-heart-broken:before,.fa-heart-crack:before{content:"\f7a9"}.fa-external-link-square-alt:before,.fa-square-up-right:before{content:"\f360"}.fa-face-kiss-beam:before,.fa-kiss-beam:before{content:"\f597"}.fa-film:before{content:"\f008"}.fa-ruler-horizontal:before{content:"\f547"}.fa-people-robbery:before{content:"\e536"}.fa-lightbulb:before{content:"\f0eb"}.fa-caret-left:before{content:"\f0d9"}.fa-circle-exclamation:before,.fa-exclamation-circle:before{content:"\f06a"}.fa-school-circle-xmark:before{content:"\e56d"}.fa-arrow-right-from-bracket:before,.fa-sign-out:before{content:"\f08b"}.fa-chevron-circle-down:before,.fa-circle-chevron-down:before{content:"\f13a"}.fa-unlock-alt:before,.fa-unlock-keyhole:before{content:"\f13e"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-headphones-alt:before,.fa-headphones-simple:before{content:"\f58f"}.fa-sitemap:before{content:"\f0e8"}.fa-circle-dollar-to-slot:before,.fa-donate:before{content:"\f4b9"}.fa-memory:before{content:"\f538"}.fa-road-spikes:before{content:"\e568"}.fa-fire-burner:before{content:"\e4f1"}.fa-flag:before{content:"\f024"}.fa-hanukiah:before{content:"\f6e6"}.fa-feather:before{content:"\f52d"}.fa-volume-down:before,.fa-volume-low:before{content:"\f027"}.fa-comment-slash:before{content:"\f4b3"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-compress:before{content:"\f066"}.fa-wheat-alt:before,.fa-wheat-awn:before{content:"\e2cd"}.fa-ankh:before{content:"\f644"}.fa-hands-holding-child:before{content:"\e4fa"}.fa-asterisk:before{content:"\2a"}.fa-check-square:before,.fa-square-check:before{content:"\f14a"}.fa-peseta-sign:before{content:"\e221"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-ghost:before{content:"\f6e2"}.fa-list-squares:before,.fa-list:before{content:"\f03a"}.fa-phone-square-alt:before,.fa-square-phone-flip:before{content:"\f87b"}.fa-cart-plus:before{content:"\f217"}.fa-gamepad:before{content:"\f11b"}.fa-circle-dot:before,.fa-dot-circle:before{content:"\f192"}.fa-dizzy:before,.fa-face-dizzy:before{content:"\f567"}.fa-egg:before{content:"\f7fb"}.fa-house-medical-circle-xmark:before{content:"\e513"}.fa-campground:before{content:"\f6bb"}.fa-folder-plus:before{content:"\f65e"}.fa-futbol-ball:before,.fa-futbol:before,.fa-soccer-ball:before{content:"\f1e3"}.fa-paint-brush:before,.fa-paintbrush:before{content:"\f1fc"}.fa-lock:before{content:"\f023"}.fa-gas-pump:before{content:"\f52f"}.fa-hot-tub-person:before,.fa-hot-tub:before{content:"\f593"}.fa-map-location:before,.fa-map-marked:before{content:"\f59f"}.fa-house-flood-water:before{content:"\e50e"}.fa-tree:before{content:"\f1bb"}.fa-bridge-lock:before{content:"\e4cc"}.fa-sack-dollar:before{content:"\f81d"}.fa-edit:before,.fa-pen-to-square:before{content:"\f044"}.fa-car-side:before{content:"\f5e4"}.fa-share-alt:before,.fa-share-nodes:before{content:"\f1e0"}.fa-heart-circle-minus:before{content:"\e4ff"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-microscope:before{content:"\f610"}.fa-sink:before{content:"\e06d"}.fa-bag-shopping:before,.fa-shopping-bag:before{content:"\f290"}.fa-arrow-down-z-a:before,.fa-sort-alpha-desc:before,.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-mitten:before{content:"\f7b5"}.fa-person-rays:before{content:"\e54d"}.fa-users:before{content:"\f0c0"}.fa-eye-slash:before{content:"\f070"}.fa-flask-vial:before{content:"\e4f3"}.fa-hand-paper:before,.fa-hand:before{content:"\f256"}.fa-om:before{content:"\f679"}.fa-worm:before{content:"\e599"}.fa-house-circle-xmark:before{content:"\e50b"}.fa-plug:before{content:"\f1e6"}.fa-chevron-up:before{content:"\f077"}.fa-hand-spock:before{content:"\f259"}.fa-stopwatch:before{content:"\f2f2"}.fa-face-kiss:before,.fa-kiss:before{content:"\f596"}.fa-bridge-circle-xmark:before{content:"\e4cb"}.fa-face-grin-tongue:before,.fa-grin-tongue:before{content:"\f589"}.fa-chess-bishop:before{content:"\f43a"}.fa-face-grin-wink:before,.fa-grin-wink:before{content:"\f58c"}.fa-deaf:before,.fa-deafness:before,.fa-ear-deaf:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-road-circle-check:before{content:"\e564"}.fa-dice-five:before{content:"\f523"}.fa-rss-square:before,.fa-square-rss:before{content:"\f143"}.fa-land-mine-on:before{content:"\e51b"}.fa-i-cursor:before{content:"\f246"}.fa-stamp:before{content:"\f5bf"}.fa-stairs:before{content:"\e289"}.fa-i:before{content:"\49"}.fa-hryvnia-sign:before,.fa-hryvnia:before{content:"\f6f2"}.fa-pills:before{content:"\f484"}.fa-face-grin-wide:before,.fa-grin-alt:before{content:"\f581"}.fa-tooth:before{content:"\f5c9"}.fa-v:before{content:"\56"}.fa-bangladeshi-taka-sign:before{content:"\e2e6"}.fa-bicycle:before{content:"\f206"}.fa-rod-asclepius:before,.fa-rod-snake:before,.fa-staff-aesculapius:before,.fa-staff-snake:before{content:"\e579"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-ambulance:before,.fa-truck-medical:before{content:"\f0f9"}.fa-wheat-awn-circle-exclamation:before{content:"\e598"}.fa-snowman:before{content:"\f7d0"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-road-barrier:before{content:"\e562"}.fa-school:before{content:"\f549"}.fa-igloo:before{content:"\f7ae"}.fa-joint:before{content:"\f595"}.fa-angle-right:before{content:"\f105"}.fa-horse:before{content:"\f6f0"}.fa-q:before{content:"\51"}.fa-g:before{content:"\47"}.fa-notes-medical:before{content:"\f481"}.fa-temperature-2:before,.fa-temperature-half:before,.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-dong-sign:before{content:"\e169"}.fa-capsules:before{content:"\f46b"}.fa-poo-bolt:before,.fa-poo-storm:before{content:"\f75a"}.fa-face-frown-open:before,.fa-frown-open:before{content:"\f57a"}.fa-hand-point-up:before{content:"\f0a6"}.fa-money-bill:before{content:"\f0d6"}.fa-bookmark:before{content:"\f02e"}.fa-align-justify:before{content:"\f039"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-helmet-un:before{content:"\e503"}.fa-bullseye:before{content:"\f140"}.fa-bacon:before{content:"\f7e5"}.fa-hand-point-down:before{content:"\f0a7"}.fa-arrow-up-from-bracket:before{content:"\e09a"}.fa-folder-blank:before,.fa-folder:before{content:"\f07b"}.fa-file-medical-alt:before,.fa-file-waveform:before{content:"\f478"}.fa-radiation:before{content:"\f7b9"}.fa-chart-simple:before{content:"\e473"}.fa-mars-stroke:before{content:"\f229"}.fa-vial:before{content:"\f492"}.fa-dashboard:before,.fa-gauge-med:before,.fa-gauge:before,.fa-tachometer-alt-average:before{content:"\f624"}.fa-magic-wand-sparkles:before,.fa-wand-magic-sparkles:before{content:"\e2ca"}.fa-e:before{content:"\45"}.fa-pen-alt:before,.fa-pen-clip:before{content:"\f305"}.fa-bridge-circle-exclamation:before{content:"\e4ca"}.fa-user:before{content:"\f007"}.fa-school-circle-check:before{content:"\e56b"}.fa-dumpster:before{content:"\f793"}.fa-shuttle-van:before,.fa-van-shuttle:before{content:"\f5b6"}.fa-building-user:before{content:"\e4da"}.fa-caret-square-left:before,.fa-square-caret-left:before{content:"\f191"}.fa-highlighter:before{content:"\f591"}.fa-key:before{content:"\f084"}.fa-bullhorn:before{content:"\f0a1"}.fa-globe:before{content:"\f0ac"}.fa-synagogue:before{content:"\f69b"}.fa-person-half-dress:before{content:"\e548"}.fa-road-bridge:before{content:"\e563"}.fa-location-arrow:before{content:"\f124"}.fa-c:before{content:"\43"}.fa-tablet-button:before{content:"\f10a"}.fa-building-lock:before{content:"\e4d6"}.fa-pizza-slice:before{content:"\f818"}.fa-money-bill-wave:before{content:"\f53a"}.fa-area-chart:before,.fa-chart-area:before{content:"\f1fe"}.fa-house-flag:before{content:"\e50d"}.fa-person-circle-minus:before{content:"\e540"}.fa-ban:before,.fa-cancel:before{content:"\f05e"}.fa-camera-rotate:before{content:"\e0d8"}.fa-air-freshener:before,.fa-spray-can-sparkles:before{content:"\f5d0"}.fa-star:before{content:"\f005"}.fa-repeat:before{content:"\f363"}.fa-cross:before{content:"\f654"}.fa-box:before{content:"\f466"}.fa-venus-mars:before{content:"\f228"}.fa-arrow-pointer:before,.fa-mouse-pointer:before{content:"\f245"}.fa-expand-arrows-alt:before,.fa-maximize:before{content:"\f31e"}.fa-charging-station:before{content:"\f5e7"}.fa-shapes:before,.fa-triangle-circle-square:before{content:"\f61f"}.fa-random:before,.fa-shuffle:before{content:"\f074"}.fa-person-running:before,.fa-running:before{content:"\f70c"}.fa-mobile-retro:before{content:"\e527"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-spider:before{content:"\f717"}.fa-hands-bound:before{content:"\e4f9"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-plane-circle-exclamation:before{content:"\e556"}.fa-x-ray:before{content:"\f497"}.fa-spell-check:before{content:"\f891"}.fa-slash:before{content:"\f715"}.fa-computer-mouse:before,.fa-mouse:before{content:"\f8cc"}.fa-arrow-right-to-bracket:before,.fa-sign-in:before{content:"\f090"}.fa-shop-slash:before,.fa-store-alt-slash:before{content:"\e070"}.fa-server:before{content:"\f233"}.fa-virus-covid-slash:before{content:"\e4a9"}.fa-shop-lock:before{content:"\e4a5"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-blender-phone:before{content:"\f6b6"}.fa-building-wheat:before{content:"\e4db"}.fa-person-breastfeeding:before{content:"\e53a"}.fa-right-to-bracket:before,.fa-sign-in-alt:before{content:"\f2f6"}.fa-venus:before{content:"\f221"}.fa-passport:before{content:"\f5ab"}.fa-heart-pulse:before,.fa-heartbeat:before{content:"\f21e"}.fa-people-carry-box:before,.fa-people-carry:before{content:"\f4ce"}.fa-temperature-high:before{content:"\f769"}.fa-microchip:before{content:"\f2db"}.fa-crown:before{content:"\f521"}.fa-weight-hanging:before{content:"\f5cd"}.fa-xmarks-lines:before{content:"\e59a"}.fa-file-prescription:before{content:"\f572"}.fa-weight-scale:before,.fa-weight:before{content:"\f496"}.fa-user-friends:before,.fa-user-group:before{content:"\f500"}.fa-arrow-up-a-z:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-chess-knight:before{content:"\f441"}.fa-face-laugh-squint:before,.fa-laugh-squint:before{content:"\f59b"}.fa-wheelchair:before{content:"\f193"}.fa-arrow-circle-up:before,.fa-circle-arrow-up:before{content:"\f0aa"}.fa-toggle-on:before{content:"\f205"}.fa-person-walking:before,.fa-walking:before{content:"\f554"}.fa-l:before{content:"\4c"}.fa-fire:before{content:"\f06d"}.fa-bed-pulse:before,.fa-procedures:before{content:"\f487"}.fa-shuttle-space:before,.fa-space-shuttle:before{content:"\f197"}.fa-face-laugh:before,.fa-laugh:before{content:"\f599"}.fa-folder-open:before{content:"\f07c"}.fa-heart-circle-plus:before{content:"\e500"}.fa-code-fork:before{content:"\e13b"}.fa-city:before{content:"\f64f"}.fa-microphone-alt:before,.fa-microphone-lines:before{content:"\f3c9"}.fa-pepper-hot:before{content:"\f816"}.fa-unlock:before{content:"\f09c"}.fa-colon-sign:before{content:"\e140"}.fa-headset:before{content:"\f590"}.fa-store-slash:before{content:"\e071"}.fa-road-circle-xmark:before{content:"\e566"}.fa-user-minus:before{content:"\f503"}.fa-mars-stroke-up:before,.fa-mars-stroke-v:before{content:"\f22a"}.fa-champagne-glasses:before,.fa-glass-cheers:before{content:"\f79f"}.fa-clipboard:before{content:"\f328"}.fa-house-circle-exclamation:before{content:"\e50a"}.fa-file-arrow-up:before,.fa-file-upload:before{content:"\f574"}.fa-wifi-3:before,.fa-wifi-strong:before,.fa-wifi:before{content:"\f1eb"}.fa-bath:before,.fa-bathtub:before{content:"\f2cd"}.fa-underline:before{content:"\f0cd"}.fa-user-edit:before,.fa-user-pen:before{content:"\f4ff"}.fa-signature:before{content:"\f5b7"}.fa-stroopwafel:before{content:"\f551"}.fa-bold:before{content:"\f032"}.fa-anchor-lock:before{content:"\e4ad"}.fa-building-ngo:before{content:"\e4d7"}.fa-manat-sign:before{content:"\e1d5"}.fa-not-equal:before{content:"\f53e"}.fa-border-style:before,.fa-border-top-left:before{content:"\f853"}.fa-map-location-dot:before,.fa-map-marked-alt:before{content:"\f5a0"}.fa-jedi:before{content:"\f669"}.fa-poll:before,.fa-square-poll-vertical:before{content:"\f681"}.fa-mug-hot:before{content:"\f7b6"}.fa-battery-car:before,.fa-car-battery:before{content:"\f5df"}.fa-gift:before{content:"\f06b"}.fa-dice-two:before{content:"\f528"}.fa-chess-queen:before{content:"\f445"}.fa-glasses:before{content:"\f530"}.fa-chess-board:before{content:"\f43c"}.fa-building-circle-check:before{content:"\e4d2"}.fa-person-chalkboard:before{content:"\e53d"}.fa-mars-stroke-h:before,.fa-mars-stroke-right:before{content:"\f22b"}.fa-hand-back-fist:before,.fa-hand-rock:before{content:"\f255"}.fa-caret-square-up:before,.fa-square-caret-up:before{content:"\f151"}.fa-cloud-showers-water:before{content:"\e4e4"}.fa-bar-chart:before,.fa-chart-bar:before{content:"\f080"}.fa-hands-bubbles:before,.fa-hands-wash:before{content:"\e05e"}.fa-less-than-equal:before{content:"\f537"}.fa-train:before{content:"\f238"}.fa-eye-low-vision:before,.fa-low-vision:before{content:"\f2a8"}.fa-crow:before{content:"\f520"}.fa-sailboat:before{content:"\e445"}.fa-window-restore:before{content:"\f2d2"}.fa-plus-square:before,.fa-square-plus:before{content:"\f0fe"}.fa-torii-gate:before{content:"\f6a1"}.fa-frog:before{content:"\f52e"}.fa-bucket:before{content:"\e4cf"}.fa-image:before{content:"\f03e"}.fa-microphone:before{content:"\f130"}.fa-cow:before{content:"\f6c8"}.fa-caret-up:before{content:"\f0d8"}.fa-screwdriver:before{content:"\f54a"}.fa-folder-closed:before{content:"\e185"}.fa-house-tsunami:before{content:"\e515"}.fa-square-nfi:before{content:"\e576"}.fa-arrow-up-from-ground-water:before{content:"\e4b5"}.fa-glass-martini-alt:before,.fa-martini-glass:before{content:"\f57b"}.fa-rotate-back:before,.fa-rotate-backward:before,.fa-rotate-left:before,.fa-undo-alt:before{content:"\f2ea"}.fa-columns:before,.fa-table-columns:before{content:"\f0db"}.fa-lemon:before{content:"\f094"}.fa-head-side-mask:before{content:"\e063"}.fa-handshake:before{content:"\f2b5"}.fa-gem:before{content:"\f3a5"}.fa-dolly-box:before,.fa-dolly:before{content:"\f472"}.fa-smoking:before{content:"\f48d"}.fa-compress-arrows-alt:before,.fa-minimize:before{content:"\f78c"}.fa-monument:before{content:"\f5a6"}.fa-snowplow:before{content:"\f7d2"}.fa-angle-double-right:before,.fa-angles-right:before{content:"\f101"}.fa-cannabis:before{content:"\f55f"}.fa-circle-play:before,.fa-play-circle:before{content:"\f144"}.fa-tablets:before{content:"\f490"}.fa-ethernet:before{content:"\f796"}.fa-eur:before,.fa-euro-sign:before,.fa-euro:before{content:"\f153"}.fa-chair:before{content:"\f6c0"}.fa-check-circle:before,.fa-circle-check:before{content:"\f058"}.fa-circle-stop:before,.fa-stop-circle:before{content:"\f28d"}.fa-compass-drafting:before,.fa-drafting-compass:before{content:"\f568"}.fa-plate-wheat:before{content:"\e55a"}.fa-icicles:before{content:"\f7ad"}.fa-person-shelter:before{content:"\e54f"}.fa-neuter:before{content:"\f22c"}.fa-id-badge:before{content:"\f2c1"}.fa-marker:before{content:"\f5a1"}.fa-face-laugh-beam:before,.fa-laugh-beam:before{content:"\f59a"}.fa-helicopter-symbol:before{content:"\e502"}.fa-universal-access:before{content:"\f29a"}.fa-chevron-circle-up:before,.fa-circle-chevron-up:before{content:"\f139"}.fa-lari-sign:before{content:"\e1c8"}.fa-volcano:before{content:"\f770"}.fa-person-walking-dashed-line-arrow-right:before{content:"\e553"}.fa-gbp:before,.fa-pound-sign:before,.fa-sterling-sign:before{content:"\f154"}.fa-viruses:before{content:"\e076"}.fa-square-person-confined:before{content:"\e577"}.fa-user-tie:before{content:"\f508"}.fa-arrow-down-long:before,.fa-long-arrow-down:before{content:"\f175"}.fa-tent-arrow-down-to-line:before{content:"\e57e"}.fa-certificate:before{content:"\f0a3"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-suitcase:before{content:"\f0f2"}.fa-person-skating:before,.fa-skating:before{content:"\f7c5"}.fa-filter-circle-dollar:before,.fa-funnel-dollar:before{content:"\f662"}.fa-camera-retro:before{content:"\f083"}.fa-arrow-circle-down:before,.fa-circle-arrow-down:before{content:"\f0ab"}.fa-arrow-right-to-file:before,.fa-file-import:before{content:"\f56f"}.fa-external-link-square:before,.fa-square-arrow-up-right:before{content:"\f14c"}.fa-box-open:before{content:"\f49e"}.fa-scroll:before{content:"\f70e"}.fa-spa:before{content:"\f5bb"}.fa-location-pin-lock:before{content:"\e51f"}.fa-pause:before{content:"\f04c"}.fa-hill-avalanche:before{content:"\e507"}.fa-temperature-0:before,.fa-temperature-empty:before,.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-bomb:before{content:"\f1e2"}.fa-registered:before{content:"\f25d"}.fa-address-card:before,.fa-contact-card:before,.fa-vcard:before{content:"\f2bb"}.fa-balance-scale-right:before,.fa-scale-unbalanced-flip:before{content:"\f516"}.fa-subscript:before{content:"\f12c"}.fa-diamond-turn-right:before,.fa-directions:before{content:"\f5eb"}.fa-burst:before{content:"\e4dc"}.fa-house-laptop:before,.fa-laptop-house:before{content:"\e066"}.fa-face-tired:before,.fa-tired:before{content:"\f5c8"}.fa-money-bills:before{content:"\e1f3"}.fa-smog:before{content:"\f75f"}.fa-crutch:before{content:"\f7f7"}.fa-cloud-arrow-up:before,.fa-cloud-upload-alt:before,.fa-cloud-upload:before{content:"\f0ee"}.fa-palette:before{content:"\f53f"}.fa-arrows-turn-right:before{content:"\e4c0"}.fa-vest:before{content:"\e085"}.fa-ferry:before{content:"\e4ea"}.fa-arrows-down-to-people:before{content:"\e4b9"}.fa-seedling:before,.fa-sprout:before{content:"\f4d8"}.fa-arrows-alt-h:before,.fa-left-right:before{content:"\f337"}.fa-boxes-packing:before{content:"\e4c7"}.fa-arrow-circle-left:before,.fa-circle-arrow-left:before{content:"\f0a8"}.fa-group-arrows-rotate:before{content:"\e4f6"}.fa-bowl-food:before{content:"\e4c6"}.fa-candy-cane:before{content:"\f786"}.fa-arrow-down-wide-short:before,.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-cloud-bolt:before,.fa-thunderstorm:before{content:"\f76c"}.fa-remove-format:before,.fa-text-slash:before{content:"\f87d"}.fa-face-smile-wink:before,.fa-smile-wink:before{content:"\f4da"}.fa-file-word:before{content:"\f1c2"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-arrows-h:before,.fa-arrows-left-right:before{content:"\f07e"}.fa-house-lock:before{content:"\e510"}.fa-cloud-arrow-down:before,.fa-cloud-download-alt:before,.fa-cloud-download:before{content:"\f0ed"}.fa-children:before{content:"\e4e1"}.fa-blackboard:before,.fa-chalkboard:before{content:"\f51b"}.fa-user-alt-slash:before,.fa-user-large-slash:before{content:"\f4fa"}.fa-envelope-open:before{content:"\f2b6"}.fa-handshake-alt-slash:before,.fa-handshake-simple-slash:before{content:"\e05f"}.fa-mattress-pillow:before{content:"\e525"}.fa-guarani-sign:before{content:"\e19a"}.fa-arrows-rotate:before,.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-fire-extinguisher:before{content:"\f134"}.fa-cruzeiro-sign:before{content:"\e152"}.fa-greater-than-equal:before{content:"\f532"}.fa-shield-alt:before,.fa-shield-halved:before{content:"\f3ed"}.fa-atlas:before,.fa-book-atlas:before{content:"\f558"}.fa-virus:before{content:"\e074"}.fa-envelope-circle-check:before{content:"\e4e8"}.fa-layer-group:before{content:"\f5fd"}.fa-arrows-to-dot:before{content:"\e4be"}.fa-archway:before{content:"\f557"}.fa-heart-circle-check:before{content:"\e4fd"}.fa-house-chimney-crack:before,.fa-house-damage:before{content:"\f6f1"}.fa-file-archive:before,.fa-file-zipper:before{content:"\f1c6"}.fa-square:before{content:"\f0c8"}.fa-glass-martini:before,.fa-martini-glass-empty:before{content:"\f000"}.fa-couch:before{content:"\f4b8"}.fa-cedi-sign:before{content:"\e0df"}.fa-italic:before{content:"\f033"}.fa-church:before{content:"\f51d"}.fa-comments-dollar:before{content:"\f653"}.fa-democrat:before{content:"\f747"}.fa-z:before{content:"\5a"}.fa-person-skiing:before,.fa-skiing:before{content:"\f7c9"}.fa-road-lock:before{content:"\e567"}.fa-a:before{content:"\41"}.fa-temperature-arrow-down:before,.fa-temperature-down:before{content:"\e03f"}.fa-feather-alt:before,.fa-feather-pointed:before{content:"\f56b"}.fa-p:before{content:"\50"}.fa-snowflake:before{content:"\f2dc"}.fa-newspaper:before{content:"\f1ea"}.fa-ad:before,.fa-rectangle-ad:before{content:"\f641"}.fa-arrow-circle-right:before,.fa-circle-arrow-right:before{content:"\f0a9"}.fa-filter-circle-xmark:before{content:"\e17b"}.fa-locust:before{content:"\e520"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-list-1-2:before,.fa-list-numeric:before,.fa-list-ol:before{content:"\f0cb"}.fa-person-dress-burst:before{content:"\e544"}.fa-money-check-alt:before,.fa-money-check-dollar:before{content:"\f53d"}.fa-vector-square:before{content:"\f5cb"}.fa-bread-slice:before{content:"\f7ec"}.fa-language:before{content:"\f1ab"}.fa-face-kiss-wink-heart:before,.fa-kiss-wink-heart:before{content:"\f598"}.fa-filter:before{content:"\f0b0"}.fa-question:before{content:"\3f"}.fa-file-signature:before{content:"\f573"}.fa-arrows-alt:before,.fa-up-down-left-right:before{content:"\f0b2"}.fa-house-chimney-user:before{content:"\e065"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-puzzle-piece:before{content:"\f12e"}.fa-money-check:before{content:"\f53c"}.fa-star-half-alt:before,.fa-star-half-stroke:before{content:"\f5c0"}.fa-code:before{content:"\f121"}.fa-glass-whiskey:before,.fa-whiskey-glass:before{content:"\f7a0"}.fa-building-circle-exclamation:before{content:"\e4d3"}.fa-magnifying-glass-chart:before{content:"\e522"}.fa-arrow-up-right-from-square:before,.fa-external-link:before{content:"\f08e"}.fa-cubes-stacked:before{content:"\e4e6"}.fa-krw:before,.fa-won-sign:before,.fa-won:before{content:"\f159"}.fa-virus-covid:before{content:"\e4a8"}.fa-austral-sign:before{content:"\e0a9"}.fa-f:before{content:"\46"}.fa-leaf:before{content:"\f06c"}.fa-road:before{content:"\f018"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-person-circle-plus:before{content:"\e541"}.fa-chart-pie:before,.fa-pie-chart:before{content:"\f200"}.fa-bolt-lightning:before{content:"\e0b7"}.fa-sack-xmark:before{content:"\e56a"}.fa-file-excel:before{content:"\f1c3"}.fa-file-contract:before{content:"\f56c"}.fa-fish-fins:before{content:"\e4f2"}.fa-building-flag:before{content:"\e4d5"}.fa-face-grin-beam:before,.fa-grin-beam:before{content:"\f582"}.fa-object-ungroup:before{content:"\f248"}.fa-poop:before{content:"\f619"}.fa-location-pin:before,.fa-map-marker:before{content:"\f041"}.fa-kaaba:before{content:"\f66b"}.fa-toilet-paper:before{content:"\f71e"}.fa-hard-hat:before,.fa-hat-hard:before,.fa-helmet-safety:before{content:"\f807"}.fa-eject:before{content:"\f052"}.fa-arrow-alt-circle-right:before,.fa-circle-right:before{content:"\f35a"}.fa-plane-circle-check:before{content:"\e555"}.fa-face-rolling-eyes:before,.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-object-group:before{content:"\f247"}.fa-chart-line:before,.fa-line-chart:before{content:"\f201"}.fa-mask-ventilator:before{content:"\e524"}.fa-arrow-right:before{content:"\f061"}.fa-map-signs:before,.fa-signs-post:before{content:"\f277"}.fa-cash-register:before{content:"\f788"}.fa-person-circle-question:before{content:"\e542"}.fa-h:before{content:"\48"}.fa-tarp:before{content:"\e57b"}.fa-screwdriver-wrench:before,.fa-tools:before{content:"\f7d9"}.fa-arrows-to-eye:before{content:"\e4bf"}.fa-plug-circle-bolt:before{content:"\e55b"}.fa-heart:before{content:"\f004"}.fa-mars-and-venus:before{content:"\f224"}.fa-home-user:before,.fa-house-user:before{content:"\e1b0"}.fa-dumpster-fire:before{content:"\f794"}.fa-house-crack:before{content:"\e3b1"}.fa-cocktail:before,.fa-martini-glass-citrus:before{content:"\f561"}.fa-face-surprise:before,.fa-surprise:before{content:"\f5c2"}.fa-bottle-water:before{content:"\e4c5"}.fa-circle-pause:before,.fa-pause-circle:before{content:"\f28b"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-apple-alt:before,.fa-apple-whole:before{content:"\f5d1"}.fa-kitchen-set:before{content:"\e51a"}.fa-r:before{content:"\52"}.fa-temperature-1:before,.fa-temperature-quarter:before,.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-cube:before{content:"\f1b2"}.fa-bitcoin-sign:before{content:"\e0b4"}.fa-shield-dog:before{content:"\e573"}.fa-solar-panel:before{content:"\f5ba"}.fa-lock-open:before{content:"\f3c1"}.fa-elevator:before{content:"\e16d"}.fa-money-bill-transfer:before{content:"\e528"}.fa-money-bill-trend-up:before{content:"\e529"}.fa-house-flood-water-circle-arrow-right:before{content:"\e50f"}.fa-poll-h:before,.fa-square-poll-horizontal:before{content:"\f682"}.fa-circle:before{content:"\f111"}.fa-backward-fast:before,.fa-fast-backward:before{content:"\f049"}.fa-recycle:before{content:"\f1b8"}.fa-user-astronaut:before{content:"\f4fb"}.fa-plane-slash:before{content:"\e069"}.fa-trademark:before{content:"\f25c"}.fa-basketball-ball:before,.fa-basketball:before{content:"\f434"}.fa-satellite-dish:before{content:"\f7c0"}.fa-arrow-alt-circle-up:before,.fa-circle-up:before{content:"\f35b"}.fa-mobile-alt:before,.fa-mobile-screen-button:before{content:"\f3cd"}.fa-volume-high:before,.fa-volume-up:before{content:"\f028"}.fa-users-rays:before{content:"\e593"}.fa-wallet:before{content:"\f555"}.fa-clipboard-check:before{content:"\f46c"}.fa-file-audio:before{content:"\f1c7"}.fa-burger:before,.fa-hamburger:before{content:"\f805"}.fa-wrench:before{content:"\f0ad"}.fa-bugs:before{content:"\e4d0"}.fa-rupee-sign:before,.fa-rupee:before{content:"\f156"}.fa-file-image:before{content:"\f1c5"}.fa-circle-question:before,.fa-question-circle:before{content:"\f059"}.fa-plane-departure:before{content:"\f5b0"}.fa-handshake-slash:before{content:"\e060"}.fa-book-bookmark:before{content:"\e0bb"}.fa-code-branch:before{content:"\f126"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-bridge:before{content:"\e4c8"}.fa-phone-alt:before,.fa-phone-flip:before{content:"\f879"}.fa-truck-front:before{content:"\e2b7"}.fa-cat:before{content:"\f6be"}.fa-anchor-circle-exclamation:before{content:"\e4ab"}.fa-truck-field:before{content:"\e58d"}.fa-route:before{content:"\f4d7"}.fa-clipboard-question:before{content:"\e4e3"}.fa-panorama:before{content:"\e209"}.fa-comment-medical:before{content:"\f7f5"}.fa-teeth-open:before{content:"\f62f"}.fa-file-circle-minus:before{content:"\e4ed"}.fa-tags:before{content:"\f02c"}.fa-wine-glass:before{content:"\f4e3"}.fa-fast-forward:before,.fa-forward-fast:before{content:"\f050"}.fa-face-meh-blank:before,.fa-meh-blank:before{content:"\f5a4"}.fa-parking:before,.fa-square-parking:before{content:"\f540"}.fa-house-signal:before{content:"\e012"}.fa-bars-progress:before,.fa-tasks-alt:before{content:"\f828"}.fa-faucet-drip:before{content:"\e006"}.fa-cart-flatbed:before,.fa-dolly-flatbed:before{content:"\f474"}.fa-ban-smoking:before,.fa-smoking-ban:before{content:"\f54d"}.fa-terminal:before{content:"\f120"}.fa-mobile-button:before{content:"\f10b"}.fa-house-medical-flag:before{content:"\e514"}.fa-basket-shopping:before,.fa-shopping-basket:before{content:"\f291"}.fa-tape:before{content:"\f4db"}.fa-bus-alt:before,.fa-bus-simple:before{content:"\f55e"}.fa-eye:before{content:"\f06e"}.fa-face-sad-cry:before,.fa-sad-cry:before{content:"\f5b3"}.fa-audio-description:before{content:"\f29e"}.fa-person-military-to-person:before{content:"\e54c"}.fa-file-shield:before{content:"\e4f0"}.fa-user-slash:before{content:"\f506"}.fa-pen:before{content:"\f304"}.fa-tower-observation:before{content:"\e586"}.fa-file-code:before{content:"\f1c9"}.fa-signal-5:before,.fa-signal-perfect:before,.fa-signal:before{content:"\f012"}.fa-bus:before{content:"\f207"}.fa-heart-circle-xmark:before{content:"\e501"}.fa-home-lg:before,.fa-house-chimney:before{content:"\e3af"}.fa-window-maximize:before{content:"\f2d0"}.fa-face-frown:before,.fa-frown:before{content:"\f119"}.fa-prescription:before{content:"\f5b1"}.fa-shop:before,.fa-store-alt:before{content:"\f54f"}.fa-floppy-disk:before,.fa-save:before{content:"\f0c7"}.fa-vihara:before{content:"\f6a7"}.fa-balance-scale-left:before,.fa-scale-unbalanced:before{content:"\f515"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-comment-dots:before,.fa-commenting:before{content:"\f4ad"}.fa-plant-wilt:before{content:"\e5aa"}.fa-diamond:before{content:"\f219"}.fa-face-grin-squint:before,.fa-grin-squint:before{content:"\f585"}.fa-hand-holding-dollar:before,.fa-hand-holding-usd:before{content:"\f4c0"}.fa-bacterium:before{content:"\e05a"}.fa-hand-pointer:before{content:"\f25a"}.fa-drum-steelpan:before{content:"\f56a"}.fa-hand-scissors:before{content:"\f257"}.fa-hands-praying:before,.fa-praying-hands:before{content:"\f684"}.fa-arrow-right-rotate:before,.fa-arrow-rotate-forward:before,.fa-arrow-rotate-right:before,.fa-redo:before{content:"\f01e"}.fa-biohazard:before{content:"\f780"}.fa-location-crosshairs:before,.fa-location:before{content:"\f601"}.fa-mars-double:before{content:"\f227"}.fa-child-dress:before{content:"\e59c"}.fa-users-between-lines:before{content:"\e591"}.fa-lungs-virus:before{content:"\e067"}.fa-face-grin-tears:before,.fa-grin-tears:before{content:"\f588"}.fa-phone:before{content:"\f095"}.fa-calendar-times:before,.fa-calendar-xmark:before{content:"\f273"}.fa-child-reaching:before{content:"\e59d"}.fa-head-side-virus:before{content:"\e064"}.fa-user-cog:before,.fa-user-gear:before{content:"\f4fe"}.fa-arrow-up-1-9:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-door-closed:before{content:"\f52a"}.fa-shield-virus:before{content:"\e06c"}.fa-dice-six:before{content:"\f526"}.fa-mosquito-net:before{content:"\e52c"}.fa-bridge-water:before{content:"\e4ce"}.fa-person-booth:before{content:"\f756"}.fa-text-width:before{content:"\f035"}.fa-hat-wizard:before{content:"\f6e8"}.fa-pen-fancy:before{content:"\f5ac"}.fa-digging:before,.fa-person-digging:before{content:"\f85e"}.fa-trash:before{content:"\f1f8"}.fa-gauge-simple-med:before,.fa-gauge-simple:before,.fa-tachometer-average:before{content:"\f629"}.fa-book-medical:before{content:"\f7e6"}.fa-poo:before{content:"\f2fe"}.fa-quote-right-alt:before,.fa-quote-right:before{content:"\f10e"}.fa-shirt:before,.fa-t-shirt:before,.fa-tshirt:before{content:"\f553"}.fa-cubes:before{content:"\f1b3"}.fa-divide:before{content:"\f529"}.fa-tenge-sign:before,.fa-tenge:before{content:"\f7d7"}.fa-headphones:before{content:"\f025"}.fa-hands-holding:before{content:"\f4c2"}.fa-hands-clapping:before{content:"\e1a8"}.fa-republican:before{content:"\f75e"}.fa-arrow-left:before{content:"\f060"}.fa-person-circle-xmark:before{content:"\e543"}.fa-ruler:before{content:"\f545"}.fa-align-left:before{content:"\f036"}.fa-dice-d6:before{content:"\f6d1"}.fa-restroom:before{content:"\f7bd"}.fa-j:before{content:"\4a"}.fa-users-viewfinder:before{content:"\e595"}.fa-file-video:before{content:"\f1c8"}.fa-external-link-alt:before,.fa-up-right-from-square:before{content:"\f35d"}.fa-table-cells:before,.fa-th:before{content:"\f00a"}.fa-file-pdf:before{content:"\f1c1"}.fa-bible:before,.fa-book-bible:before{content:"\f647"}.fa-o:before{content:"\4f"}.fa-medkit:before,.fa-suitcase-medical:before{content:"\f0fa"}.fa-user-secret:before{content:"\f21b"}.fa-otter:before{content:"\f700"}.fa-female:before,.fa-person-dress:before{content:"\f182"}.fa-comment-dollar:before{content:"\f651"}.fa-briefcase-clock:before,.fa-business-time:before{content:"\f64a"}.fa-table-cells-large:before,.fa-th-large:before{content:"\f009"}.fa-book-tanakh:before,.fa-tanakh:before{content:"\f827"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-clipboard-user:before{content:"\f7f3"}.fa-child:before{content:"\f1ae"}.fa-lira-sign:before{content:"\f195"}.fa-satellite:before{content:"\f7bf"}.fa-plane-lock:before{content:"\e558"}.fa-tag:before{content:"\f02b"}.fa-comment:before{content:"\f075"}.fa-birthday-cake:before,.fa-cake-candles:before,.fa-cake:before{content:"\f1fd"}.fa-envelope:before{content:"\f0e0"}.fa-angle-double-up:before,.fa-angles-up:before{content:"\f102"}.fa-paperclip:before{content:"\f0c6"}.fa-arrow-right-to-city:before{content:"\e4b3"}.fa-ribbon:before{content:"\f4d6"}.fa-lungs:before{content:"\f604"}.fa-arrow-up-9-1:before,.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-litecoin-sign:before{content:"\e1d3"}.fa-border-none:before{content:"\f850"}.fa-circle-nodes:before{content:"\e4e2"}.fa-parachute-box:before{content:"\f4cd"}.fa-indent:before{content:"\f03c"}.fa-truck-field-un:before{content:"\e58e"}.fa-hourglass-empty:before,.fa-hourglass:before{content:"\f254"}.fa-mountain:before{content:"\f6fc"}.fa-user-doctor:before,.fa-user-md:before{content:"\f0f0"}.fa-circle-info:before,.fa-info-circle:before{content:"\f05a"}.fa-cloud-meatball:before{content:"\f73b"}.fa-camera-alt:before,.fa-camera:before{content:"\f030"}.fa-square-virus:before{content:"\e578"}.fa-meteor:before{content:"\f753"}.fa-car-on:before{content:"\e4dd"}.fa-sleigh:before{content:"\f7cc"}.fa-arrow-down-1-9:before,.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-hand-holding-droplet:before,.fa-hand-holding-water:before{content:"\f4c1"}.fa-water:before{content:"\f773"}.fa-calendar-check:before{content:"\f274"}.fa-braille:before{content:"\f2a1"}.fa-prescription-bottle-alt:before,.fa-prescription-bottle-medical:before{content:"\f486"}.fa-landmark:before{content:"\f66f"}.fa-truck:before{content:"\f0d1"}.fa-crosshairs:before{content:"\f05b"}.fa-person-cane:before{content:"\e53c"}.fa-tent:before{content:"\e57d"}.fa-vest-patches:before{content:"\e086"}.fa-check-double:before{content:"\f560"}.fa-arrow-down-a-z:before,.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-money-bill-wheat:before{content:"\e52a"}.fa-cookie:before{content:"\f563"}.fa-arrow-left-rotate:before,.fa-arrow-rotate-back:before,.fa-arrow-rotate-backward:before,.fa-arrow-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-hard-drive:before,.fa-hdd:before{content:"\f0a0"}.fa-face-grin-squint-tears:before,.fa-grin-squint-tears:before{content:"\f586"}.fa-dumbbell:before{content:"\f44b"}.fa-list-alt:before,.fa-rectangle-list:before{content:"\f022"}.fa-tarp-droplet:before{content:"\e57c"}.fa-house-medical-circle-check:before{content:"\e511"}.fa-person-skiing-nordic:before,.fa-skiing-nordic:before{content:"\f7ca"}.fa-calendar-plus:before{content:"\f271"}.fa-plane-arrival:before{content:"\f5af"}.fa-arrow-alt-circle-left:before,.fa-circle-left:before{content:"\f359"}.fa-subway:before,.fa-train-subway:before{content:"\f239"}.fa-chart-gantt:before{content:"\e0e4"}.fa-indian-rupee-sign:before,.fa-indian-rupee:before,.fa-inr:before{content:"\e1bc"}.fa-crop-alt:before,.fa-crop-simple:before{content:"\f565"}.fa-money-bill-1:before,.fa-money-bill-alt:before{content:"\f3d1"}.fa-left-long:before,.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-dna:before{content:"\f471"}.fa-virus-slash:before{content:"\e075"}.fa-minus:before,.fa-subtract:before{content:"\f068"}.fa-chess:before{content:"\f439"}.fa-arrow-left-long:before,.fa-long-arrow-left:before{content:"\f177"}.fa-plug-circle-check:before{content:"\e55c"}.fa-street-view:before{content:"\f21d"}.fa-franc-sign:before{content:"\e18f"}.fa-volume-off:before{content:"\f026"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before,.fa-hands-american-sign-language-interpreting:before,.fa-hands-asl-interpreting:before{content:"\f2a3"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-droplet-slash:before,.fa-tint-slash:before{content:"\f5c7"}.fa-mosque:before{content:"\f678"}.fa-mosquito:before{content:"\e52b"}.fa-star-of-david:before{content:"\f69a"}.fa-person-military-rifle:before{content:"\e54b"}.fa-cart-shopping:before,.fa-shopping-cart:before{content:"\f07a"}.fa-vials:before{content:"\f493"}.fa-plug-circle-plus:before{content:"\e55f"}.fa-place-of-worship:before{content:"\f67f"}.fa-grip-vertical:before{content:"\f58e"}.fa-arrow-turn-up:before,.fa-level-up:before{content:"\f148"}.fa-u:before{content:"\55"}.fa-square-root-alt:before,.fa-square-root-variable:before{content:"\f698"}.fa-clock-four:before,.fa-clock:before{content:"\f017"}.fa-backward-step:before,.fa-step-backward:before{content:"\f048"}.fa-pallet:before{content:"\f482"}.fa-faucet:before{content:"\e005"}.fa-baseball-bat-ball:before{content:"\f432"}.fa-s:before{content:"\53"}.fa-timeline:before{content:"\e29c"}.fa-keyboard:before{content:"\f11c"}.fa-caret-down:before{content:"\f0d7"}.fa-clinic-medical:before,.fa-house-chimney-medical:before{content:"\f7f2"}.fa-temperature-3:before,.fa-temperature-three-quarters:before,.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-mobile-android-alt:before,.fa-mobile-screen:before{content:"\f3cf"}.fa-plane-up:before{content:"\e22d"}.fa-piggy-bank:before{content:"\f4d3"}.fa-battery-3:before,.fa-battery-half:before{content:"\f242"}.fa-mountain-city:before{content:"\e52e"}.fa-coins:before{content:"\f51e"}.fa-khanda:before{content:"\f66d"}.fa-sliders-h:before,.fa-sliders:before{content:"\f1de"}.fa-folder-tree:before{content:"\f802"}.fa-network-wired:before{content:"\f6ff"}.fa-map-pin:before{content:"\f276"}.fa-hamsa:before{content:"\f665"}.fa-cent-sign:before{content:"\e3f5"}.fa-flask:before{content:"\f0c3"}.fa-person-pregnant:before{content:"\e31e"}.fa-wand-sparkles:before{content:"\f72b"}.fa-ellipsis-v:before,.fa-ellipsis-vertical:before{content:"\f142"}.fa-ticket:before{content:"\f145"}.fa-power-off:before{content:"\f011"}.fa-long-arrow-alt-right:before,.fa-right-long:before{content:"\f30b"}.fa-flag-usa:before{content:"\f74d"}.fa-laptop-file:before{content:"\e51d"}.fa-teletype:before,.fa-tty:before{content:"\f1e4"}.fa-diagram-next:before{content:"\e476"}.fa-person-rifle:before{content:"\e54e"}.fa-house-medical-circle-exclamation:before{content:"\e512"}.fa-closed-captioning:before{content:"\f20a"}.fa-hiking:before,.fa-person-hiking:before{content:"\f6ec"}.fa-venus-double:before{content:"\f226"}.fa-images:before{content:"\f302"}.fa-calculator:before{content:"\f1ec"}.fa-people-pulling:before{content:"\e535"}.fa-n:before{content:"\4e"}.fa-cable-car:before,.fa-tram:before{content:"\f7da"}.fa-cloud-rain:before{content:"\f73d"}.fa-building-circle-xmark:before{content:"\e4d4"}.fa-ship:before{content:"\f21a"}.fa-arrows-down-to-line:before{content:"\e4b8"}.fa-download:before{content:"\f019"}.fa-face-grin:before,.fa-grin:before{content:"\f580"}.fa-backspace:before,.fa-delete-left:before{content:"\f55a"}.fa-eye-dropper-empty:before,.fa-eye-dropper:before,.fa-eyedropper:before{content:"\f1fb"}.fa-file-circle-check:before{content:"\e5a0"}.fa-forward:before{content:"\f04e"}.fa-mobile-android:before,.fa-mobile-phone:before,.fa-mobile:before{content:"\f3ce"}.fa-face-meh:before,.fa-meh:before{content:"\f11a"}.fa-align-center:before{content:"\f037"}.fa-book-dead:before,.fa-book-skull:before{content:"\f6b7"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-heart-circle-exclamation:before{content:"\e4fe"}.fa-home-alt:before,.fa-home-lg-alt:before,.fa-home:before,.fa-house:before{content:"\f015"}.fa-calendar-week:before{content:"\f784"}.fa-laptop-medical:before{content:"\f812"}.fa-b:before{content:"\42"}.fa-file-medical:before{content:"\f477"}.fa-dice-one:before{content:"\f525"}.fa-kiwi-bird:before{content:"\f535"}.fa-arrow-right-arrow-left:before,.fa-exchange:before{content:"\f0ec"}.fa-redo-alt:before,.fa-rotate-forward:before,.fa-rotate-right:before{content:"\f2f9"}.fa-cutlery:before,.fa-utensils:before{content:"\f2e7"}.fa-arrow-up-wide-short:before,.fa-sort-amount-up:before{content:"\f161"}.fa-mill-sign:before{content:"\e1ed"}.fa-bowl-rice:before{content:"\e2eb"}.fa-skull:before{content:"\f54c"}.fa-broadcast-tower:before,.fa-tower-broadcast:before{content:"\f519"}.fa-truck-pickup:before{content:"\f63c"}.fa-long-arrow-alt-up:before,.fa-up-long:before{content:"\f30c"}.fa-stop:before{content:"\f04d"}.fa-code-merge:before{content:"\f387"}.fa-upload:before{content:"\f093"}.fa-hurricane:before{content:"\f751"}.fa-mound:before{content:"\e52d"}.fa-toilet-portable:before{content:"\e583"}.fa-compact-disc:before{content:"\f51f"}.fa-file-arrow-down:before,.fa-file-download:before{content:"\f56d"}.fa-caravan:before{content:"\f8ff"}.fa-shield-cat:before{content:"\e572"}.fa-bolt:before,.fa-zap:before{content:"\f0e7"}.fa-glass-water:before{content:"\e4f4"}.fa-oil-well:before{content:"\e532"}.fa-vault:before{content:"\e2c5"}.fa-mars:before{content:"\f222"}.fa-toilet:before{content:"\f7d8"}.fa-plane-circle-xmark:before{content:"\e557"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen-sign:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble-sign:before,.fa-ruble:before{content:"\f158"}.fa-sun:before{content:"\f185"}.fa-guitar:before{content:"\f7a6"}.fa-face-laugh-wink:before,.fa-laugh-wink:before{content:"\f59c"}.fa-horse-head:before{content:"\f7ab"}.fa-bore-hole:before{content:"\e4c3"}.fa-industry:before{content:"\f275"}.fa-arrow-alt-circle-down:before,.fa-circle-down:before{content:"\f358"}.fa-arrows-turn-to-dots:before{content:"\e4c1"}.fa-florin-sign:before{content:"\e184"}.fa-arrow-down-short-wide:before,.fa-sort-amount-desc:before,.fa-sort-amount-down-alt:before{content:"\f884"}.fa-less-than:before{content:"\3c"}.fa-angle-down:before{content:"\f107"}.fa-car-tunnel:before{content:"\e4de"}.fa-head-side-cough:before{content:"\e061"}.fa-grip-lines:before{content:"\f7a4"}.fa-thumbs-down:before{content:"\f165"}.fa-user-lock:before{content:"\f502"}.fa-arrow-right-long:before,.fa-long-arrow-right:before{content:"\f178"}.fa-anchor-circle-xmark:before{content:"\e4ac"}.fa-ellipsis-h:before,.fa-ellipsis:before{content:"\f141"}.fa-chess-pawn:before{content:"\f443"}.fa-first-aid:before,.fa-kit-medical:before{content:"\f479"}.fa-person-through-window:before{content:"\e5a9"}.fa-toolbox:before{content:"\f552"}.fa-hands-holding-circle:before{content:"\e4fb"}.fa-bug:before{content:"\f188"}.fa-credit-card-alt:before,.fa-credit-card:before{content:"\f09d"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-hand-holding-hand:before{content:"\e4f7"}.fa-book-open-reader:before,.fa-book-reader:before{content:"\f5da"}.fa-mountain-sun:before{content:"\e52f"}.fa-arrows-left-right-to-line:before{content:"\e4ba"}.fa-dice-d20:before{content:"\f6cf"}.fa-truck-droplet:before{content:"\e58c"}.fa-file-circle-xmark:before{content:"\e5a1"}.fa-temperature-arrow-up:before,.fa-temperature-up:before{content:"\e040"}.fa-medal:before{content:"\f5a2"}.fa-bed:before{content:"\f236"}.fa-h-square:before,.fa-square-h:before{content:"\f0fd"}.fa-podcast:before{content:"\f2ce"}.fa-temperature-4:before,.fa-temperature-full:before,.fa-thermometer-4:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-bell:before{content:"\f0f3"}.fa-superscript:before{content:"\f12b"}.fa-plug-circle-xmark:before{content:"\e560"}.fa-star-of-life:before{content:"\f621"}.fa-phone-slash:before{content:"\f3dd"}.fa-paint-roller:before{content:"\f5aa"}.fa-hands-helping:before,.fa-handshake-angle:before{content:"\f4c4"}.fa-location-dot:before,.fa-map-marker-alt:before{content:"\f3c5"}.fa-file:before{content:"\f15b"}.fa-greater-than:before{content:"\3e"}.fa-person-swimming:before,.fa-swimmer:before{content:"\f5c4"}.fa-arrow-down:before{content:"\f063"}.fa-droplet:before,.fa-tint:before{content:"\f043"}.fa-eraser:before{content:"\f12d"}.fa-earth-america:before,.fa-earth-americas:before,.fa-earth:before,.fa-globe-americas:before{content:"\f57d"}.fa-person-burst:before{content:"\e53b"}.fa-dove:before{content:"\f4ba"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-socks:before{content:"\f696"}.fa-inbox:before{content:"\f01c"}.fa-section:before{content:"\e447"}.fa-gauge-high:before,.fa-tachometer-alt-fast:before,.fa-tachometer-alt:before{content:"\f625"}.fa-envelope-open-text:before{content:"\f658"}.fa-hospital-alt:before,.fa-hospital-wide:before,.fa-hospital:before{content:"\f0f8"}.fa-wine-bottle:before{content:"\f72f"}.fa-chess-rook:before{content:"\f447"}.fa-bars-staggered:before,.fa-reorder:before,.fa-stream:before{content:"\f550"}.fa-dharmachakra:before{content:"\f655"}.fa-hotdog:before{content:"\f80f"}.fa-blind:before,.fa-person-walking-with-cane:before{content:"\f29d"}.fa-drum:before{content:"\f569"}.fa-ice-cream:before{content:"\f810"}.fa-heart-circle-bolt:before{content:"\e4fc"}.fa-fax:before{content:"\f1ac"}.fa-paragraph:before{content:"\f1dd"}.fa-check-to-slot:before,.fa-vote-yea:before{content:"\f772"}.fa-star-half:before{content:"\f089"}.fa-boxes-alt:before,.fa-boxes-stacked:before,.fa-boxes:before{content:"\f468"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-assistive-listening-systems:before,.fa-ear-listen:before{content:"\f2a2"}.fa-tree-city:before{content:"\e587"}.fa-play:before{content:"\f04b"}.fa-font:before{content:"\f031"}.fa-rupiah-sign:before{content:"\e23d"}.fa-magnifying-glass:before,.fa-search:before{content:"\f002"}.fa-ping-pong-paddle-ball:before,.fa-table-tennis-paddle-ball:before,.fa-table-tennis:before{content:"\f45d"}.fa-diagnoses:before,.fa-person-dots-from-line:before{content:"\f470"}.fa-trash-can-arrow-up:before,.fa-trash-restore-alt:before{content:"\f82a"}.fa-naira-sign:before{content:"\e1f6"}.fa-cart-arrow-down:before{content:"\f218"}.fa-walkie-talkie:before{content:"\f8ef"}.fa-file-edit:before,.fa-file-pen:before{content:"\f31c"}.fa-receipt:before{content:"\f543"}.fa-pen-square:before,.fa-pencil-square:before,.fa-square-pen:before{content:"\f14b"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-person-circle-exclamation:before{content:"\e53f"}.fa-chevron-down:before{content:"\f078"}.fa-battery-5:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-skull-crossbones:before{content:"\f714"}.fa-code-compare:before{content:"\e13a"}.fa-list-dots:before,.fa-list-ul:before{content:"\f0ca"}.fa-school-lock:before{content:"\e56f"}.fa-tower-cell:before{content:"\e585"}.fa-down-long:before,.fa-long-arrow-alt-down:before{content:"\f309"}.fa-ranking-star:before{content:"\e561"}.fa-chess-king:before{content:"\f43f"}.fa-person-harassing:before{content:"\e549"}.fa-brazilian-real-sign:before{content:"\e46c"}.fa-landmark-alt:before,.fa-landmark-dome:before{content:"\f752"}.fa-arrow-up:before{content:"\f062"}.fa-television:before,.fa-tv-alt:before,.fa-tv:before{content:"\f26c"}.fa-shrimp:before{content:"\e448"}.fa-list-check:before,.fa-tasks:before{content:"\f0ae"}.fa-jug-detergent:before{content:"\e519"}.fa-circle-user:before,.fa-user-circle:before{content:"\f2bd"}.fa-user-shield:before{content:"\f505"}.fa-wind:before{content:"\f72e"}.fa-car-burst:before,.fa-car-crash:before{content:"\f5e1"}.fa-y:before{content:"\59"}.fa-person-snowboarding:before,.fa-snowboarding:before{content:"\f7ce"}.fa-shipping-fast:before,.fa-truck-fast:before{content:"\f48b"}.fa-fish:before{content:"\f578"}.fa-user-graduate:before{content:"\f501"}.fa-adjust:before,.fa-circle-half-stroke:before{content:"\f042"}.fa-clapperboard:before{content:"\e131"}.fa-circle-radiation:before,.fa-radiation-alt:before{content:"\f7ba"}.fa-baseball-ball:before,.fa-baseball:before{content:"\f433"}.fa-jet-fighter-up:before{content:"\e518"}.fa-diagram-project:before,.fa-project-diagram:before{content:"\f542"}.fa-copy:before{content:"\f0c5"}.fa-volume-mute:before,.fa-volume-times:before,.fa-volume-xmark:before{content:"\f6a9"}.fa-hand-sparkles:before{content:"\e05d"}.fa-grip-horizontal:before,.fa-grip:before{content:"\f58d"}.fa-share-from-square:before,.fa-share-square:before{content:"\f14d"}.fa-child-combatant:before,.fa-child-rifle:before{content:"\e4e0"}.fa-gun:before{content:"\e19b"}.fa-phone-square:before,.fa-square-phone:before{content:"\f098"}.fa-add:before,.fa-plus:before{content:"\2b"}.fa-expand:before{content:"\f065"}.fa-computer:before{content:"\e4e5"}.fa-close:before,.fa-multiply:before,.fa-remove:before,.fa-times:before,.fa-xmark:before{content:"\f00d"}.fa-arrows-up-down-left-right:before,.fa-arrows:before{content:"\f047"}.fa-chalkboard-teacher:before,.fa-chalkboard-user:before{content:"\f51c"}.fa-peso-sign:before{content:"\e222"}.fa-building-shield:before{content:"\e4d8"}.fa-baby:before{content:"\f77c"}.fa-users-line:before{content:"\e592"}.fa-quote-left-alt:before,.fa-quote-left:before{content:"\f10d"}.fa-tractor:before{content:"\f722"}.fa-trash-arrow-up:before,.fa-trash-restore:before{content:"\f829"}.fa-arrow-down-up-lock:before{content:"\e4b0"}.fa-lines-leaning:before{content:"\e51e"}.fa-ruler-combined:before{content:"\f546"}.fa-copyright:before{content:"\f1f9"}.fa-equals:before{content:"\3d"}.fa-blender:before{content:"\f517"}.fa-teeth:before{content:"\f62e"}.fa-ils:before,.fa-shekel-sign:before,.fa-shekel:before,.fa-sheqel-sign:before,.fa-sheqel:before{content:"\f20b"}.fa-map:before{content:"\f279"}.fa-rocket:before{content:"\f135"}.fa-photo-film:before,.fa-photo-video:before{content:"\f87c"}.fa-folder-minus:before{content:"\f65d"}.fa-store:before{content:"\f54e"}.fa-arrow-trend-up:before{content:"\e098"}.fa-plug-circle-minus:before{content:"\e55e"}.fa-sign-hanging:before,.fa-sign:before{content:"\f4d9"}.fa-bezier-curve:before{content:"\f55b"}.fa-bell-slash:before{content:"\f1f6"}.fa-tablet-android:before,.fa-tablet:before{content:"\f3fb"}.fa-school-flag:before{content:"\e56e"}.fa-fill:before{content:"\f575"}.fa-angle-up:before{content:"\f106"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-holly-berry:before{content:"\f7aa"}.fa-chevron-left:before{content:"\f053"}.fa-bacteria:before{content:"\e059"}.fa-hand-lizard:before{content:"\f258"}.fa-notdef:before{content:"\e1fe"}.fa-disease:before{content:"\f7fa"}.fa-briefcase-medical:before{content:"\f469"}.fa-genderless:before{content:"\f22d"}.fa-chevron-right:before{content:"\f054"}.fa-retweet:before{content:"\f079"}.fa-car-alt:before,.fa-car-rear:before{content:"\f5de"}.fa-pump-soap:before{content:"\e06b"}.fa-video-slash:before{content:"\f4e2"}.fa-battery-2:before,.fa-battery-quarter:before{content:"\f243"}.fa-radio:before{content:"\f8d7"}.fa-baby-carriage:before,.fa-carriage-baby:before{content:"\f77d"}.fa-traffic-light:before{content:"\f637"}.fa-thermometer:before{content:"\f491"}.fa-vr-cardboard:before{content:"\f729"}.fa-hand-middle-finger:before{content:"\f806"}.fa-percent:before,.fa-percentage:before{content:"\25"}.fa-truck-moving:before{content:"\f4df"}.fa-glass-water-droplet:before{content:"\e4f5"}.fa-display:before{content:"\e163"}.fa-face-smile:before,.fa-smile:before{content:"\f118"}.fa-thumb-tack:before,.fa-thumbtack:before{content:"\f08d"}.fa-trophy:before{content:"\f091"}.fa-person-praying:before,.fa-pray:before{content:"\f683"}.fa-hammer:before{content:"\f6e3"}.fa-hand-peace:before{content:"\f25b"}.fa-rotate:before,.fa-sync-alt:before{content:"\f2f1"}.fa-spinner:before{content:"\f110"}.fa-robot:before{content:"\f544"}.fa-peace:before{content:"\f67c"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-warehouse:before{content:"\f494"}.fa-arrow-up-right-dots:before{content:"\e4b7"}.fa-splotch:before{content:"\f5bc"}.fa-face-grin-hearts:before,.fa-grin-hearts:before{content:"\f584"}.fa-dice-four:before{content:"\f524"}.fa-sim-card:before{content:"\f7c4"}.fa-transgender-alt:before,.fa-transgender:before{content:"\f225"}.fa-mercury:before{content:"\f223"}.fa-arrow-turn-down:before,.fa-level-down:before{content:"\f149"}.fa-person-falling-burst:before{content:"\e547"}.fa-award:before{content:"\f559"}.fa-ticket-alt:before,.fa-ticket-simple:before{content:"\f3ff"}.fa-building:before{content:"\f1ad"}.fa-angle-double-left:before,.fa-angles-left:before{content:"\f100"}.fa-qrcode:before{content:"\f029"}.fa-clock-rotate-left:before,.fa-history:before{content:"\f1da"}.fa-face-grin-beam-sweat:before,.fa-grin-beam-sweat:before{content:"\f583"}.fa-arrow-right-from-file:before,.fa-file-export:before{content:"\f56e"}.fa-shield-blank:before,.fa-shield:before{content:"\f132"}.fa-arrow-up-short-wide:before,.fa-sort-amount-up-alt:before{content:"\f885"}.fa-house-medical:before{content:"\e3b2"}.fa-golf-ball-tee:before,.fa-golf-ball:before{content:"\f450"}.fa-chevron-circle-left:before,.fa-circle-chevron-left:before{content:"\f137"}.fa-house-chimney-window:before{content:"\e00d"}.fa-pen-nib:before{content:"\f5ad"}.fa-tent-arrow-turn-left:before{content:"\e580"}.fa-tents:before{content:"\e582"}.fa-magic:before,.fa-wand-magic:before{content:"\f0d0"}.fa-dog:before{content:"\f6d3"}.fa-carrot:before{content:"\f787"}.fa-moon:before{content:"\f186"}.fa-wine-glass-alt:before,.fa-wine-glass-empty:before{content:"\f5ce"}.fa-cheese:before{content:"\f7ef"}.fa-yin-yang:before{content:"\f6ad"}.fa-music:before{content:"\f001"}.fa-code-commit:before{content:"\f386"}.fa-temperature-low:before{content:"\f76b"}.fa-biking:before,.fa-person-biking:before{content:"\f84a"}.fa-broom:before{content:"\f51a"}.fa-shield-heart:before{content:"\e574"}.fa-gopuram:before{content:"\f664"}.fa-earth-oceania:before,.fa-globe-oceania:before{content:"\e47b"}.fa-square-xmark:before,.fa-times-square:before,.fa-xmark-square:before{content:"\f2d3"}.fa-hashtag:before{content:"\23"}.fa-expand-alt:before,.fa-up-right-and-down-left-from-center:before{content:"\f424"}.fa-oil-can:before{content:"\f613"}.fa-t:before{content:"\54"}.fa-hippo:before{content:"\f6ed"}.fa-chart-column:before{content:"\e0e3"}.fa-infinity:before{content:"\f534"}.fa-vial-circle-check:before{content:"\e596"}.fa-person-arrow-down-to-line:before{content:"\e538"}.fa-voicemail:before{content:"\f897"}.fa-fan:before{content:"\f863"}.fa-person-walking-luggage:before{content:"\e554"}.fa-arrows-alt-v:before,.fa-up-down:before{content:"\f338"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-calendar:before{content:"\f133"}.fa-trailer:before{content:"\e041"}.fa-bahai:before,.fa-haykal:before{content:"\f666"}.fa-sd-card:before{content:"\f7c2"}.fa-dragon:before{content:"\f6d5"}.fa-shoe-prints:before{content:"\f54b"}.fa-circle-plus:before,.fa-plus-circle:before{content:"\f055"}.fa-face-grin-tongue-wink:before,.fa-grin-tongue-wink:before{content:"\f58b"}.fa-hand-holding:before{content:"\f4bd"}.fa-plug-circle-exclamation:before{content:"\e55d"}.fa-chain-broken:before,.fa-chain-slash:before,.fa-link-slash:before,.fa-unlink:before{content:"\f127"}.fa-clone:before{content:"\f24d"}.fa-person-walking-arrow-loop-left:before{content:"\e551"}.fa-arrow-up-z-a:before,.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-fire-alt:before,.fa-fire-flame-curved:before{content:"\f7e4"}.fa-tornado:before{content:"\f76f"}.fa-file-circle-plus:before{content:"\e494"}.fa-book-quran:before,.fa-quran:before{content:"\f687"}.fa-anchor:before{content:"\f13d"}.fa-border-all:before{content:"\f84c"}.fa-angry:before,.fa-face-angry:before{content:"\f556"}.fa-cookie-bite:before{content:"\f564"}.fa-arrow-trend-down:before{content:"\e097"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-draw-polygon:before{content:"\f5ee"}.fa-balance-scale:before,.fa-scale-balanced:before{content:"\f24e"}.fa-gauge-simple-high:before,.fa-tachometer-fast:before,.fa-tachometer:before{content:"\f62a"}.fa-shower:before{content:"\f2cc"}.fa-desktop-alt:before,.fa-desktop:before{content:"\f390"}.fa-m:before{content:"\4d"}.fa-table-list:before,.fa-th-list:before{content:"\f00b"}.fa-comment-sms:before,.fa-sms:before{content:"\f7cd"}.fa-book:before{content:"\f02d"}.fa-user-plus:before{content:"\f234"}.fa-check:before{content:"\f00c"}.fa-battery-4:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-house-circle-check:before{content:"\e509"}.fa-angle-left:before{content:"\f104"}.fa-diagram-successor:before{content:"\e47a"}.fa-truck-arrow-right:before{content:"\e58b"}.fa-arrows-split-up-and-left:before{content:"\e4bc"}.fa-fist-raised:before,.fa-hand-fist:before{content:"\f6de"}.fa-cloud-moon:before{content:"\f6c3"}.fa-briefcase:before{content:"\f0b1"}.fa-person-falling:before{content:"\e546"}.fa-image-portrait:before,.fa-portrait:before{content:"\f3e0"}.fa-user-tag:before{content:"\f507"}.fa-rug:before{content:"\e569"}.fa-earth-europe:before,.fa-globe-europe:before{content:"\f7a2"}.fa-cart-flatbed-suitcase:before,.fa-luggage-cart:before{content:"\f59d"}.fa-rectangle-times:before,.fa-rectangle-xmark:before,.fa-times-rectangle:before,.fa-window-close:before{content:"\f410"}.fa-baht-sign:before{content:"\e0ac"}.fa-book-open:before{content:"\f518"}.fa-book-journal-whills:before,.fa-journal-whills:before{content:"\f66a"}.fa-handcuffs:before{content:"\e4f8"}.fa-exclamation-triangle:before,.fa-triangle-exclamation:before,.fa-warning:before{content:"\f071"}.fa-database:before{content:"\f1c0"}.fa-arrow-turn-right:before,.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-bottle-droplet:before{content:"\e4c4"}.fa-mask-face:before{content:"\e1d7"}.fa-hill-rockslide:before{content:"\e508"}.fa-exchange-alt:before,.fa-right-left:before{content:"\f362"}.fa-paper-plane:before{content:"\f1d8"}.fa-road-circle-exclamation:before{content:"\e565"}.fa-dungeon:before{content:"\f6d9"}.fa-align-right:before{content:"\f038"}.fa-money-bill-1-wave:before,.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-life-ring:before{content:"\f1cd"}.fa-hands:before,.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-calendar-day:before{content:"\f783"}.fa-ladder-water:before,.fa-swimming-pool:before,.fa-water-ladder:before{content:"\f5c5"}.fa-arrows-up-down:before,.fa-arrows-v:before{content:"\f07d"}.fa-face-grimace:before,.fa-grimace:before{content:"\f57f"}.fa-wheelchair-alt:before,.fa-wheelchair-move:before{content:"\e2ce"}.fa-level-down-alt:before,.fa-turn-down:before{content:"\f3be"}.fa-person-walking-arrow-right:before{content:"\e552"}.fa-envelope-square:before,.fa-square-envelope:before{content:"\f199"}.fa-dice:before{content:"\f522"}.fa-bowling-ball:before{content:"\f436"}.fa-brain:before{content:"\f5dc"}.fa-band-aid:before,.fa-bandage:before{content:"\f462"}.fa-calendar-minus:before{content:"\f272"}.fa-circle-xmark:before,.fa-times-circle:before,.fa-xmark-circle:before{content:"\f057"}.fa-gifts:before{content:"\f79c"}.fa-hotel:before{content:"\f594"}.fa-earth-asia:before,.fa-globe-asia:before{content:"\f57e"}.fa-id-card-alt:before,.fa-id-card-clip:before{content:"\f47f"}.fa-magnifying-glass-plus:before,.fa-search-plus:before{content:"\f00e"}.fa-thumbs-up:before{content:"\f164"}.fa-user-clock:before{content:"\f4fd"}.fa-allergies:before,.fa-hand-dots:before{content:"\f461"}.fa-file-invoice:before{content:"\f570"}.fa-window-minimize:before{content:"\f2d1"}.fa-coffee:before,.fa-mug-saucer:before{content:"\f0f4"}.fa-brush:before{content:"\f55d"}.fa-mask:before{content:"\f6fa"}.fa-magnifying-glass-minus:before,.fa-search-minus:before{content:"\f010"}.fa-ruler-vertical:before{content:"\f548"}.fa-user-alt:before,.fa-user-large:before{content:"\f406"}.fa-train-tram:before{content:"\e5b4"}.fa-user-nurse:before{content:"\f82f"}.fa-syringe:before{content:"\f48e"}.fa-cloud-sun:before{content:"\f6c4"}.fa-stopwatch-20:before{content:"\e06f"}.fa-square-full:before{content:"\f45c"}.fa-magnet:before{content:"\f076"}.fa-jar:before{content:"\e516"}.fa-note-sticky:before,.fa-sticky-note:before{content:"\f249"}.fa-bug-slash:before{content:"\e490"}.fa-arrow-up-from-water-pump:before{content:"\e4b6"}.fa-bone:before{content:"\f5d7"}.fa-user-injured:before{content:"\f728"}.fa-face-sad-tear:before,.fa-sad-tear:before{content:"\f5b4"}.fa-plane:before{content:"\f072"}.fa-tent-arrows-down:before{content:"\e581"}.fa-exclamation:before{content:"\21"}.fa-arrows-spin:before{content:"\e4bb"}.fa-print:before{content:"\f02f"}.fa-try:before,.fa-turkish-lira-sign:before,.fa-turkish-lira:before{content:"\e2bb"}.fa-dollar-sign:before,.fa-dollar:before,.fa-usd:before{content:"\24"}.fa-x:before{content:"\58"}.fa-magnifying-glass-dollar:before,.fa-search-dollar:before{content:"\f688"}.fa-users-cog:before,.fa-users-gear:before{content:"\f509"}.fa-person-military-pointing:before{content:"\e54a"}.fa-bank:before,.fa-building-columns:before,.fa-institution:before,.fa-museum:before,.fa-university:before{content:"\f19c"}.fa-umbrella:before{content:"\f0e9"}.fa-trowel:before{content:"\e589"}.fa-d:before{content:"\44"}.fa-stapler:before{content:"\e5af"}.fa-masks-theater:before,.fa-theater-masks:before{content:"\f630"}.fa-kip-sign:before{content:"\e1c4"}.fa-hand-point-left:before{content:"\f0a5"}.fa-handshake-alt:before,.fa-handshake-simple:before{content:"\f4c6"}.fa-fighter-jet:before,.fa-jet-fighter:before{content:"\f0fb"}.fa-share-alt-square:before,.fa-square-share-nodes:before{content:"\f1e1"}.fa-barcode:before{content:"\f02a"}.fa-plus-minus:before{content:"\e43c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-person-circle-check:before{content:"\e53e"}.fa-level-up-alt:before,.fa-turn-up:before{content:"\f3bf"}
+.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero:before{content:"\f3d0"}.fa-hooli:before{content:"\f427"}.fa-yelp:before{content:"\f1e9"}.fa-cc-visa:before{content:"\f1f0"}.fa-lastfm:before{content:"\f202"}.fa-shopware:before{content:"\f5b5"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-aws:before{content:"\f375"}.fa-redhat:before{content:"\f7bc"}.fa-yoast:before{content:"\f2b1"}.fa-cloudflare:before{content:"\e07d"}.fa-ups:before{content:"\f7e0"}.fa-wpexplorer:before{content:"\f2de"}.fa-dyalog:before{content:"\f399"}.fa-bity:before{content:"\f37a"}.fa-stackpath:before{content:"\f842"}.fa-buysellads:before{content:"\f20d"}.fa-first-order:before{content:"\f2b0"}.fa-modx:before{content:"\f285"}.fa-guilded:before{content:"\e07e"}.fa-vnv:before{content:"\f40b"}.fa-js-square:before,.fa-square-js:before{content:"\f3b9"}.fa-microsoft:before{content:"\f3ca"}.fa-qq:before{content:"\f1d6"}.fa-orcid:before{content:"\f8d2"}.fa-java:before{content:"\f4e4"}.fa-invision:before{content:"\f7b0"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-centercode:before{content:"\f380"}.fa-glide-g:before{content:"\f2a6"}.fa-drupal:before{content:"\f1a9"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-unity:before{content:"\e049"}.fa-whmcs:before{content:"\f40d"}.fa-rocketchat:before{content:"\f3e8"}.fa-vk:before{content:"\f189"}.fa-untappd:before{content:"\f405"}.fa-mailchimp:before{content:"\f59e"}.fa-css3-alt:before{content:"\f38b"}.fa-reddit-square:before,.fa-square-reddit:before{content:"\f1a2"}.fa-vimeo-v:before{content:"\f27d"}.fa-contao:before{content:"\f26d"}.fa-square-font-awesome:before{content:"\e5ad"}.fa-deskpro:before{content:"\f38f"}.fa-sistrix:before{content:"\f3ee"}.fa-instagram-square:before,.fa-square-instagram:before{content:"\e055"}.fa-battle-net:before{content:"\f835"}.fa-the-red-yeti:before{content:"\f69d"}.fa-hacker-news-square:before,.fa-square-hacker-news:before{content:"\f3af"}.fa-edge:before{content:"\f282"}.fa-threads:before{content:"\e618"}.fa-napster:before{content:"\f3d2"}.fa-snapchat-square:before,.fa-square-snapchat:before{content:"\f2ad"}.fa-google-plus-g:before{content:"\f0d5"}.fa-artstation:before{content:"\f77a"}.fa-markdown:before{content:"\f60f"}.fa-sourcetree:before{content:"\f7d3"}.fa-google-plus:before{content:"\f2b3"}.fa-diaspora:before{content:"\f791"}.fa-foursquare:before{content:"\f180"}.fa-stack-overflow:before{content:"\f16c"}.fa-github-alt:before{content:"\f113"}.fa-phoenix-squadron:before{content:"\f511"}.fa-pagelines:before{content:"\f18c"}.fa-algolia:before{content:"\f36c"}.fa-red-river:before{content:"\f3e3"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-safari:before{content:"\f267"}.fa-google:before{content:"\f1a0"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-atlassian:before{content:"\f77b"}.fa-linkedin-in:before{content:"\f0e1"}.fa-digital-ocean:before{content:"\f391"}.fa-nimblr:before{content:"\f5a8"}.fa-chromecast:before{content:"\f838"}.fa-evernote:before{content:"\f839"}.fa-hacker-news:before{content:"\f1d4"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-adversal:before{content:"\f36a"}.fa-creative-commons:before{content:"\f25e"}.fa-watchman-monitoring:before{content:"\e087"}.fa-fonticons:before{content:"\f280"}.fa-weixin:before{content:"\f1d7"}.fa-shirtsinbulk:before{content:"\f214"}.fa-codepen:before{content:"\f1cb"}.fa-git-alt:before{content:"\f841"}.fa-lyft:before{content:"\f3c3"}.fa-rev:before{content:"\f5b2"}.fa-windows:before{content:"\f17a"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-square-viadeo:before,.fa-viadeo-square:before{content:"\f2aa"}.fa-meetup:before{content:"\f2e0"}.fa-centos:before{content:"\f789"}.fa-adn:before{content:"\f170"}.fa-cloudsmith:before{content:"\f384"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-dribbble-square:before,.fa-square-dribbble:before{content:"\f397"}.fa-codiepie:before{content:"\f284"}.fa-node:before{content:"\f419"}.fa-mix:before{content:"\f3cb"}.fa-steam:before{content:"\f1b6"}.fa-cc-apple-pay:before{content:"\f416"}.fa-scribd:before{content:"\f28a"}.fa-debian:before{content:"\e60b"}.fa-openid:before{content:"\f19b"}.fa-instalod:before{content:"\e081"}.fa-expeditedssl:before{content:"\f23e"}.fa-sellcast:before{content:"\f2da"}.fa-square-twitter:before,.fa-twitter-square:before{content:"\f081"}.fa-r-project:before{content:"\f4f7"}.fa-delicious:before{content:"\f1a5"}.fa-freebsd:before{content:"\f3a4"}.fa-vuejs:before{content:"\f41f"}.fa-accusoft:before{content:"\f369"}.fa-ioxhost:before{content:"\f208"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-app-store:before{content:"\f36f"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-itunes-note:before{content:"\f3b5"}.fa-golang:before{content:"\e40f"}.fa-kickstarter:before{content:"\f3bb"}.fa-grav:before{content:"\f2d6"}.fa-weibo:before{content:"\f18a"}.fa-uncharted:before{content:"\e084"}.fa-firstdraft:before{content:"\f3a1"}.fa-square-youtube:before,.fa-youtube-square:before{content:"\f431"}.fa-wikipedia-w:before{content:"\f266"}.fa-rendact:before,.fa-wpressr:before{content:"\f3e4"}.fa-angellist:before{content:"\f209"}.fa-galactic-republic:before{content:"\f50c"}.fa-nfc-directional:before{content:"\e530"}.fa-skype:before{content:"\f17e"}.fa-joget:before{content:"\f3b7"}.fa-fedora:before{content:"\f798"}.fa-stripe-s:before{content:"\f42a"}.fa-meta:before{content:"\e49b"}.fa-laravel:before{content:"\f3bd"}.fa-hotjar:before{content:"\f3b1"}.fa-bluetooth-b:before{content:"\f294"}.fa-sticker-mule:before{content:"\f3f7"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-hips:before{content:"\f452"}.fa-behance:before{content:"\f1b4"}.fa-reddit:before{content:"\f1a1"}.fa-discord:before{content:"\f392"}.fa-chrome:before{content:"\f268"}.fa-app-store-ios:before{content:"\f370"}.fa-cc-discover:before{content:"\f1f2"}.fa-wpbeginner:before{content:"\f297"}.fa-confluence:before{content:"\f78d"}.fa-mdb:before{content:"\f8ca"}.fa-dochub:before{content:"\f394"}.fa-accessible-icon:before{content:"\f368"}.fa-ebay:before{content:"\f4f4"}.fa-amazon:before{content:"\f270"}.fa-unsplash:before{content:"\e07c"}.fa-yarn:before{content:"\f7e3"}.fa-square-steam:before,.fa-steam-square:before{content:"\f1b7"}.fa-500px:before{content:"\f26e"}.fa-square-vimeo:before,.fa-vimeo-square:before{content:"\f194"}.fa-asymmetrik:before{content:"\f372"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-gratipay:before{content:"\f184"}.fa-apple:before{content:"\f179"}.fa-hive:before{content:"\e07f"}.fa-gitkraken:before{content:"\f3a6"}.fa-keybase:before{content:"\f4f5"}.fa-apple-pay:before{content:"\f415"}.fa-padlet:before{content:"\e4a0"}.fa-amazon-pay:before{content:"\f42c"}.fa-github-square:before,.fa-square-github:before{content:"\f092"}.fa-stumbleupon:before{content:"\f1a4"}.fa-fedex:before{content:"\f797"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-shopify:before{content:"\e057"}.fa-neos:before{content:"\f612"}.fa-square-threads:before{content:"\e619"}.fa-hackerrank:before{content:"\f5f7"}.fa-researchgate:before{content:"\f4f8"}.fa-swift:before{content:"\f8e1"}.fa-angular:before{content:"\f420"}.fa-speakap:before{content:"\f3f3"}.fa-angrycreative:before{content:"\f36e"}.fa-y-combinator:before{content:"\f23b"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-gitlab-square:before,.fa-square-gitlab:before{content:"\e5ae"}.fa-studiovinari:before{content:"\f3f8"}.fa-pied-piper:before{content:"\f2ae"}.fa-wordpress:before{content:"\f19a"}.fa-product-hunt:before{content:"\f288"}.fa-firefox:before{content:"\f269"}.fa-linode:before{content:"\f2b8"}.fa-goodreads:before{content:"\f3a8"}.fa-odnoklassniki-square:before,.fa-square-odnoklassniki:before{content:"\f264"}.fa-jsfiddle:before{content:"\f1cc"}.fa-sith:before{content:"\f512"}.fa-themeisle:before{content:"\f2b2"}.fa-page4:before{content:"\f3d7"}.fa-hashnode:before{content:"\e499"}.fa-react:before{content:"\f41b"}.fa-cc-paypal:before{content:"\f1f4"}.fa-squarespace:before{content:"\f5be"}.fa-cc-stripe:before{content:"\f1f5"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-bitcoin:before{content:"\f379"}.fa-keycdn:before{content:"\f3ba"}.fa-opera:before{content:"\f26a"}.fa-itch-io:before{content:"\f83a"}.fa-umbraco:before{content:"\f8e8"}.fa-galactic-senate:before{content:"\f50d"}.fa-ubuntu:before{content:"\f7df"}.fa-draft2digital:before{content:"\f396"}.fa-stripe:before{content:"\f429"}.fa-houzz:before{content:"\f27c"}.fa-gg:before{content:"\f260"}.fa-dhl:before{content:"\f790"}.fa-pinterest-square:before,.fa-square-pinterest:before{content:"\f0d3"}.fa-xing:before{content:"\f168"}.fa-blackberry:before{content:"\f37b"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-playstation:before{content:"\f3df"}.fa-quinscape:before{content:"\f459"}.fa-less:before{content:"\f41d"}.fa-blogger-b:before{content:"\f37d"}.fa-opencart:before{content:"\f23d"}.fa-vine:before{content:"\f1ca"}.fa-paypal:before{content:"\f1ed"}.fa-gitlab:before{content:"\f296"}.fa-typo3:before{content:"\f42b"}.fa-reddit-alien:before{content:"\f281"}.fa-yahoo:before{content:"\f19e"}.fa-dailymotion:before{content:"\e052"}.fa-affiliatetheme:before{content:"\f36b"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-bootstrap:before{content:"\f836"}.fa-odnoklassniki:before{content:"\f263"}.fa-nfc-symbol:before{content:"\e531"}.fa-ethereum:before{content:"\f42e"}.fa-speaker-deck:before{content:"\f83c"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-patreon:before{content:"\f3d9"}.fa-avianex:before{content:"\f374"}.fa-ello:before{content:"\f5f1"}.fa-gofore:before{content:"\f3a7"}.fa-bimobject:before{content:"\f378"}.fa-facebook-f:before{content:"\f39e"}.fa-google-plus-square:before,.fa-square-google-plus:before{content:"\f0d4"}.fa-mandalorian:before{content:"\f50f"}.fa-first-order-alt:before{content:"\f50a"}.fa-osi:before{content:"\f41a"}.fa-google-wallet:before{content:"\f1ee"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-periscope:before{content:"\f3da"}.fa-fulcrum:before{content:"\f50b"}.fa-cloudscale:before{content:"\f383"}.fa-forumbee:before{content:"\f211"}.fa-mizuni:before{content:"\f3cc"}.fa-schlix:before{content:"\f3ea"}.fa-square-xing:before,.fa-xing-square:before{content:"\f169"}.fa-bandcamp:before{content:"\f2d5"}.fa-wpforms:before{content:"\f298"}.fa-cloudversify:before{content:"\f385"}.fa-usps:before{content:"\f7e1"}.fa-megaport:before{content:"\f5a3"}.fa-magento:before{content:"\f3c4"}.fa-spotify:before{content:"\f1bc"}.fa-optin-monster:before{content:"\f23c"}.fa-fly:before{content:"\f417"}.fa-aviato:before{content:"\f421"}.fa-itunes:before{content:"\f3b4"}.fa-cuttlefish:before{content:"\f38c"}.fa-blogger:before{content:"\f37c"}.fa-flickr:before{content:"\f16e"}.fa-viber:before{content:"\f409"}.fa-soundcloud:before{content:"\f1be"}.fa-digg:before{content:"\f1a6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-symfony:before{content:"\f83d"}.fa-maxcdn:before{content:"\f136"}.fa-etsy:before{content:"\f2d7"}.fa-facebook-messenger:before{content:"\f39f"}.fa-audible:before{content:"\f373"}.fa-think-peaks:before{content:"\f731"}.fa-bilibili:before{content:"\e3d9"}.fa-erlang:before{content:"\f39d"}.fa-x-twitter:before{content:"\e61b"}.fa-cotton-bureau:before{content:"\f89e"}.fa-dashcube:before{content:"\f210"}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-stack-exchange:before{content:"\f18d"}.fa-elementor:before{content:"\f430"}.fa-pied-piper-square:before,.fa-square-pied-piper:before{content:"\e01e"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-palfed:before{content:"\f3d8"}.fa-superpowers:before{content:"\f2dd"}.fa-resolving:before{content:"\f3e7"}.fa-xbox:before{content:"\f412"}.fa-searchengin:before{content:"\f3eb"}.fa-tiktok:before{content:"\e07b"}.fa-facebook-square:before,.fa-square-facebook:before{content:"\f082"}.fa-renren:before{content:"\f18b"}.fa-linux:before{content:"\f17c"}.fa-glide:before{content:"\f2a5"}.fa-linkedin:before{content:"\f08c"}.fa-hubspot:before{content:"\f3b2"}.fa-deploydog:before{content:"\f38e"}.fa-twitch:before{content:"\f1e8"}.fa-ravelry:before{content:"\f2d9"}.fa-mixer:before{content:"\e056"}.fa-lastfm-square:before,.fa-square-lastfm:before{content:"\f203"}.fa-vimeo:before{content:"\f40a"}.fa-mendeley:before{content:"\f7b3"}.fa-uniregistry:before{content:"\f404"}.fa-figma:before{content:"\f799"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-dropbox:before{content:"\f16b"}.fa-instagram:before{content:"\f16d"}.fa-cmplid:before{content:"\e360"}.fa-facebook:before{content:"\f09a"}.fa-gripfire:before{content:"\f3ac"}.fa-jedi-order:before{content:"\f50e"}.fa-uikit:before{content:"\f403"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-phabricator:before{content:"\f3db"}.fa-ussunnah:before{content:"\f407"}.fa-earlybirds:before{content:"\f39a"}.fa-trade-federation:before{content:"\f513"}.fa-autoprefixer:before{content:"\f41c"}.fa-whatsapp:before{content:"\f232"}.fa-slideshare:before{content:"\f1e7"}.fa-google-play:before{content:"\f3ab"}.fa-viadeo:before{content:"\f2a9"}.fa-line:before{content:"\f3c0"}.fa-google-drive:before{content:"\f3aa"}.fa-servicestack:before{content:"\f3ec"}.fa-simplybuilt:before{content:"\f215"}.fa-bitbucket:before{content:"\f171"}.fa-imdb:before{content:"\f2d8"}.fa-deezer:before{content:"\e077"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-jira:before{content:"\f7b1"}.fa-docker:before{content:"\f395"}.fa-screenpal:before{content:"\e570"}.fa-bluetooth:before{content:"\f293"}.fa-gitter:before{content:"\f426"}.fa-d-and-d:before{content:"\f38d"}.fa-microblog:before{content:"\e01a"}.fa-cc-diners-club:before{content:"\f24c"}.fa-gg-circle:before{content:"\f261"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-yandex:before{content:"\f413"}.fa-readme:before{content:"\f4d5"}.fa-html5:before{content:"\f13b"}.fa-sellsy:before{content:"\f213"}.fa-sass:before{content:"\f41e"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-buromobelexperte:before{content:"\f37f"}.fa-salesforce:before{content:"\f83b"}.fa-octopus-deploy:before{content:"\e082"}.fa-medapps:before{content:"\f3c6"}.fa-ns8:before{content:"\f3d5"}.fa-pinterest-p:before{content:"\f231"}.fa-apper:before{content:"\f371"}.fa-fort-awesome:before{content:"\f286"}.fa-waze:before{content:"\f83f"}.fa-cc-jcb:before{content:"\f24b"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-rust:before{content:"\e07a"}.fa-wix:before{content:"\f5cf"}.fa-behance-square:before,.fa-square-behance:before{content:"\f1b5"}.fa-supple:before{content:"\f3f9"}.fa-rebel:before{content:"\f1d0"}.fa-css3:before{content:"\f13c"}.fa-staylinked:before{content:"\f3f5"}.fa-kaggle:before{content:"\f5fa"}.fa-space-awesome:before{content:"\e5ac"}.fa-deviantart:before{content:"\f1bd"}.fa-cpanel:before{content:"\f388"}.fa-goodreads-g:before{content:"\f3a9"}.fa-git-square:before,.fa-square-git:before{content:"\f1d2"}.fa-square-tumblr:before,.fa-tumblr-square:before{content:"\f174"}.fa-trello:before{content:"\f181"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-get-pocket:before{content:"\f265"}.fa-perbyte:before{content:"\e083"}.fa-grunt:before{content:"\f3ad"}.fa-weebly:before{content:"\f5cc"}.fa-connectdevelop:before{content:"\f20e"}.fa-leanpub:before{content:"\f212"}.fa-black-tie:before{content:"\f27e"}.fa-themeco:before{content:"\f5c6"}.fa-python:before{content:"\f3e2"}.fa-android:before{content:"\f17b"}.fa-bots:before{content:"\e340"}.fa-free-code-camp:before{content:"\f2c5"}.fa-hornbill:before{content:"\f592"}.fa-js:before{content:"\f3b8"}.fa-ideal:before{content:"\e013"}.fa-git:before{content:"\f1d3"}.fa-dev:before{content:"\f6cc"}.fa-sketch:before{content:"\f7c6"}.fa-yandex-international:before{content:"\f414"}.fa-cc-amex:before{content:"\f1f3"}.fa-uber:before{content:"\f402"}.fa-github:before{content:"\f09b"}.fa-php:before{content:"\f457"}.fa-alipay:before{content:"\f642"}.fa-youtube:before{content:"\f167"}.fa-skyatlas:before{content:"\f216"}.fa-firefox-browser:before{content:"\e007"}.fa-replyd:before{content:"\f3e6"}.fa-suse:before{content:"\f7d6"}.fa-jenkins:before{content:"\f3b6"}.fa-twitter:before{content:"\f099"}.fa-rockrms:before{content:"\f3e9"}.fa-pinterest:before{content:"\f0d2"}.fa-buffer:before{content:"\f837"}.fa-npm:before{content:"\f3d4"}.fa-yammer:before{content:"\f840"}.fa-btc:before{content:"\f15a"}.fa-dribbble:before{content:"\f17d"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-internet-explorer:before{content:"\f26b"}.fa-stubber:before{content:"\e5c7"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-old-republic:before{content:"\f510"}.fa-odysee:before{content:"\e5c6"}.fa-square-whatsapp:before,.fa-whatsapp-square:before{content:"\f40c"}.fa-node-js:before{content:"\f3d3"}.fa-edge-legacy:before{content:"\e078"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-medrt:before{content:"\f3c8"}.fa-usb:before{content:"\f287"}.fa-tumblr:before{content:"\f173"}.fa-vaadin:before{content:"\f408"}.fa-quora:before{content:"\f2c4"}.fa-square-x-twitter:before{content:"\e61a"}.fa-reacteurope:before{content:"\f75d"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-amilia:before{content:"\f36d"}.fa-mixcloud:before{content:"\f289"}.fa-flipboard:before{content:"\f44d"}.fa-viacoin:before{content:"\f237"}.fa-critical-role:before{content:"\f6c9"}.fa-sitrox:before{content:"\e44a"}.fa-discourse:before{content:"\f393"}.fa-joomla:before{content:"\f1aa"}.fa-mastodon:before{content:"\f4f6"}.fa-airbnb:before{content:"\f834"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-buy-n-large:before{content:"\f8a6"}.fa-gulp:before{content:"\f3ae"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-strava:before{content:"\f428"}.fa-ember:before{content:"\f423"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-teamspeak:before{content:"\f4f9"}.fa-pushed:before{content:"\f3e1"}.fa-wordpress-simple:before{content:"\f411"}.fa-nutritionix:before{content:"\f3d6"}.fa-wodu:before{content:"\e088"}.fa-google-pay:before{content:"\e079"}.fa-intercom:before{content:"\f7af"}.fa-zhihu:before{content:"\f63f"}.fa-korvue:before{content:"\f42f"}.fa-pix:before{content:"\e43a"}.fa-steam-symbol:before{content:"\f3f6"}:host,:root{--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
\ No newline at end of file
diff --git a/wms/contract-repair/styles/style.css b/wms/contract-repair/styles/style.css
new file mode 100644
index 00000000..7cc8f7dd
--- /dev/null
+++ b/wms/contract-repair/styles/style.css
@@ -0,0 +1,837 @@
+@charset "UTF-8";
+main {
+ display: flex;
+ justify-content: flex-start;
+ margin-top: -20px;
+}
+main [x-cloak] {
+ display: none !important;
+}
+main > .sidebar {
+ width: 300px;
+ min-height: 100vh;
+ border-right: 1px #ddd solid;
+ box-shadow: 0px 0px 5px #ddd;
+ padding: 50px 20px;
+}
+main > .sidebar button {
+ display: block;
+ outline: none;
+ border: none;
+ color: #1E74FD;
+ background-color: transparent;
+ margin-bottom: 20px;
+ border-bottom: 1px #ccc solid;
+ opacity: 0.65;
+}
+main > .sidebar button.active {
+ opacity: 1;
+}
+main > .sidebar button:hover {
+ opacity: 1;
+}
+main > .sidebar a {
+ display: block;
+ width: 120px;
+ height: 35px;
+ text-align: center;
+ line-height: 35px;
+ text-decoration: none;
+ background-color: #1E74FD;
+ color: #fff;
+ margin-top: 50px;
+}
+main .inputDiv {
+ padding: 30px;
+ display: flex;
+ flex-direction: column;
+}
+main .inputDiv label {
+ margin-bottom: 10px;
+}
+main .inputDiv label input,
+main .inputDiv label select {
+ border: 1px #aaa solid;
+ outline: none;
+ border-radius: 5px;
+ width: 220px;
+ height: 32px;
+ padding: 0 10px;
+}
+main .inputDiv label button {
+ background-color: #1E74FD;
+ color: #fff;
+ outline: none;
+ border: none;
+ border: 1px #ccc solid;
+ width: 220px;
+ height: 32px;
+ font-weight: 6500;
+ margin-top: 15px;
+}
+main .contract-install-component,
+main .contract-material-component {
+ width: 100%;
+ max-width: 816px;
+ margin: 30px auto;
+ background-color: #f7f7f7 !important;
+}
+main .contract-install-component p,
+main .contract-material-component p {
+ margin: 0;
+}
+main .contract-install-component > .btn-list,
+main .contract-material-component > .btn-list {
+ display: flex;
+ align-items: center;
+}
+main .contract-install-component > .btn-list > button,
+main .contract-material-component > .btn-list > button {
+ padding: 8px;
+ margin: 0 4px;
+}
+main .contract-install-component > .contract,
+main .contract-material-component > .contract {
+ background: #fff;
+ width: 100%;
+ margin-top: 15px;
+ padding: 20px;
+ font-family: "標楷體";
+}
+main .contract-install-component > .contract > h2,
+main .contract-material-component > .contract > h2 {
+ font-size: 18pt;
+ text-align: center;
+}
+main .contract-install-component > .contract br,
+main .contract-material-component > .contract br {
+ line-height: 2.5;
+}
+main .contract-install-component > .contract .d-flex,
+main .contract-material-component > .contract .d-flex {
+ display: flex;
+ align-items: center;
+}
+main .contract-install-component > .contract .mouseover,
+main .contract-material-component > .contract .mouseover {
+ background-color: #f1f1f1;
+ cursor: pointer;
+}
+main .contract-install-component > .contract div,
+main .contract-install-component > .contract section,
+main .contract-material-component > .contract div,
+main .contract-material-component > .contract section {
+ font-size: 12pt;
+ line-height: 2.5;
+}
+main .contract-install-component > .contract div.party,
+main .contract-install-component > .contract section.party,
+main .contract-material-component > .contract div.party,
+main .contract-material-component > .contract section.party {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+main .contract-install-component > .contract div.party .company-name,
+main .contract-install-component > .contract section.party .company-name,
+main .contract-material-component > .contract div.party .company-name,
+main .contract-material-component > .contract section.party .company-name {
+ text-indent: 80pt;
+}
+main .contract-install-component > .contract div.party .notes,
+main .contract-install-component > .contract section.party .notes,
+main .contract-material-component > .contract div.party .notes,
+main .contract-material-component > .contract section.party .notes {
+ margin-right: 25%;
+ white-space: nowrap;
+}
+main .contract-install-component > .contract div.list-content,
+main .contract-install-component > .contract section.list-content,
+main .contract-material-component > .contract div.list-content,
+main .contract-material-component > .contract section.list-content {
+ margin-left: 70px;
+}
+main .contract-install-component > .contract div.list-title,
+main .contract-install-component > .contract section.list-title,
+main .contract-material-component > .contract div.list-title,
+main .contract-material-component > .contract section.list-title {
+ display: flex;
+ align-items: flex-start;
+}
+main .contract-install-component > .contract div.list-title > strong,
+main .contract-install-component > .contract section.list-title > strong,
+main .contract-material-component > .contract div.list-title > strong,
+main .contract-material-component > .contract section.list-title > strong {
+ min-width: 70px;
+}
+main .contract-install-component > .contract p,
+main .contract-install-component > .contract article,
+main .contract-install-component > .contract div,
+main .contract-material-component > .contract p,
+main .contract-material-component > .contract article,
+main .contract-material-component > .contract div {
+ position: relative;
+ display: block;
+}
+main .contract-install-component > .contract .date,
+main .contract-material-component > .contract .date {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ margin-top: 300px;
+}
+main .contract-install-component > .contract .date p,
+main .contract-material-component > .contract .date p {
+ width: 50%;
+ letter-spacing: 20px;
+}
+main .contract-install-component > .contract .date > .ml,
+main .contract-material-component > .contract .date > .ml {
+ width: 50%;
+ display: flex;
+ justify-content: space-between;
+ flex-direction: row-reverse;
+}
+main .contract-install-component > .contract .buttons,
+main .contract-material-component > .contract .buttons {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: flex;
+ z-index: 9;
+}
+main .contract-install-component > .contract .buttons > button,
+main .contract-material-component > .contract .buttons > button {
+ width: 30px;
+ height: 30px;
+ border-radius: 5px;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 2px #fff solid;
+ outline: none;
+ color: #fff;
+ margin: 0 1px;
+}
+main .contract-install-component > .contract .buttons > button > i,
+main .contract-material-component > .contract .buttons > button > i {
+ font-size: 12px;
+}
+main .contract-install-component > .contract .buttons > button.edit,
+main .contract-material-component > .contract .buttons > button.edit {
+ background-color: #5BC0DE;
+}
+main .contract-install-component > .contract .buttons > button.add,
+main .contract-material-component > .contract .buttons > button.add {
+ background-color: #F0AD4E;
+}
+main .contract-install-component > .contract .buttons > button.delete,
+main .contract-material-component > .contract .buttons > button.delete {
+ background-color: rgb(211, 0, 0);
+}
+main .contract-install-component > .contract table,
+main .contract-material-component > .contract table {
+ border: none;
+ margin-top: 30px;
+ font-family: "標楷體";
+ width: 800px;
+}
+main .contract-install-component > .contract table tr:nth-child(even),
+main .contract-install-component > .contract table tr:nth-child(odd),
+main .contract-material-component > .contract table tr:nth-child(even),
+main .contract-material-component > .contract table tr:nth-child(odd) {
+ background-color: #fff;
+}
+main .contract-install-component > .contract table tr,
+main .contract-material-component > .contract table tr {
+ font-size: 12pt;
+ width: 100%;
+ position: relative;
+}
+main .contract-install-component > .contract table tr.mouseover,
+main .contract-material-component > .contract table tr.mouseover {
+ background-color: #f3f3f3;
+}
+main .contract-install-component > .contract table tr h2,
+main .contract-material-component > .contract table tr h2 {
+ font-size: 18pt;
+}
+main .contract-install-component > .contract table tr td,
+main .contract-material-component > .contract table tr td {
+ width: 100%;
+ height: 100%;
+ line-height: 2;
+ display: flex;
+}
+main .contract-install-component > .contract table tr td.center,
+main .contract-material-component > .contract table tr td.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+main .contract-install-component > .contract table tr td.list,
+main .contract-material-component > .contract table tr td.list {
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+ display: flex;
+}
+main .contract-install-component > .contract table tr td.list span,
+main .contract-material-component > .contract table tr td.list span {
+ width: 100px;
+ min-height: 100%;
+ display: block;
+}
+main .contract-install-component > .contract table tr td.list > p,
+main .contract-material-component > .contract table tr td.list > p {
+ display: block;
+ text-align: justify;
+}
+main .contract-install-component > .contract table tr td.list div,
+main .contract-install-component > .contract table tr td.list article,
+main .contract-material-component > .contract table tr td.list div,
+main .contract-material-component > .contract table tr td.list article {
+ max-width: calc(100% - 100px);
+ white-space: normal;
+}
+main .contract-install-component > .contract table tr td.list div input[type=text],
+main .contract-install-component > .contract table tr td.list div input[type=number],
+main .contract-install-component > .contract table tr td.list div input,
+main .contract-install-component > .contract table tr td.list article input[type=text],
+main .contract-install-component > .contract table tr td.list article input[type=number],
+main .contract-install-component > .contract table tr td.list article input,
+main .contract-material-component > .contract table tr td.list div input[type=text],
+main .contract-material-component > .contract table tr td.list div input[type=number],
+main .contract-material-component > .contract table tr td.list div input,
+main .contract-material-component > .contract table tr td.list article input[type=text],
+main .contract-material-component > .contract table tr td.list article input[type=number],
+main .contract-material-component > .contract table tr td.list article input {
+ border: none !important;
+ border-bottom: 1px #222 solid !important;
+ width: 50px;
+ outline: none;
+ text-align: center;
+}
+main .contract-install-component > .contract table tr td.list div.text-justify,
+main .contract-install-component > .contract table tr td.list article.text-justify,
+main .contract-material-component > .contract table tr td.list div.text-justify,
+main .contract-material-component > .contract table tr td.list article.text-justify {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+}
+main .contract-install-component > .contract table tr.date td > div,
+main .contract-material-component > .contract table tr.date td > div {
+ width: 100%;
+ text-align: right;
+}
+main .contract-install-component > .contract table tr.date td > div.text-justify,
+main .contract-material-component > .contract table tr.date td > div.text-justify {
+ display: flex;
+ justify-content: space-between;
+}
+main .contract-install-component > .contract table td,
+main .contract-install-component > .contract table th,
+main .contract-material-component > .contract table td,
+main .contract-material-component > .contract table th {
+ padding: 8px;
+}
+@keyframes modelanim {
+ 0% {
+ opacity: 0;
+ }
+}
+main .contract-model {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+ animation: modelanim 0.2s linear;
+}
+main .contract-model > .contract-back {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+}
+main .contract-model > .contract-content {
+ z-index: 999;
+ max-width: 600px;
+ width: 100%;
+ border-radius: 6px;
+ overflow: hidden;
+ background-color: white;
+}
+main .contract-model > .contract-content > .model-header {
+ width: 100%;
+ background-color: #1E74FD;
+ height: 38px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 15px;
+}
+main .contract-model > .contract-content > .model-header > i {
+ float: right;
+ color: rgba(255, 255, 255, 0.7058823529);
+ cursor: pointer;
+}
+main .contract-model > .contract-content > .model-header > i:hover {
+ color: #fff;
+}
+main .contract-model > .contract-content > .model-header > span {
+ color: #fff;
+}
+main .contract-model > .contract-content > .content {
+ padding: 30px;
+}
+main .contract-model > .contract-content > .content textarea {
+ width: 100%;
+ resize: vertical;
+ height: 150px;
+ border: 1px #ccc solid;
+ outline: none;
+ border-radius: 6px;
+}
+main .rebtn,
+main .prviewbtn {
+ background-color: #5BC0DE;
+ color: #fff;
+ outline: none;
+ border: none;
+ border: 1px #ccc solid;
+ width: 100px;
+ height: 32px;
+ font-weight: 600;
+ border-radius: 6px;
+ margin-right: 5px;
+}
+main .prviewbtn {
+ background-color: #2E6DA4;
+}
+
+input[type=checkbox].scorll,
+input[type=radio].scorll {
+ position: relative;
+ width: 50px;
+ height: 25px;
+ outline: none;
+ background: linear-gradient(to right, #bbb, #999);
+ -webkit-appearance: none;
+ cursor: pointer;
+ border-radius: 20px;
+}
+input[type=checkbox].scorll::before,
+input[type=radio].scorll::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 25px;
+ height: 25px;
+ background: #fff;
+ border-radius: 50%;
+ transform: scale(0.98, 0.96);
+ transition: 0.5s;
+}
+input[type=checkbox].scorll:checked,
+input[type=radio].scorll:checked {
+ background: linear-gradient(to right, #5BC0DE, #2E6DA4);
+}
+input[type=checkbox].scorll:checked::before,
+input[type=radio].scorll:checked::before {
+ left: 25px;
+}
+input[type=checkbox].scorll::after,
+input[type=radio].scorll::after {
+ content: "";
+}
+
+.prview table {
+ border: none;
+ margin-top: 30px;
+ font-family: "標楷體";
+ width: 800px;
+ border: 1px #ccc solid;
+}
+.prview table tr:nth-child(even),
+.prview table tr:nth-child(odd) {
+ background-color: #fff;
+}
+.prview table tr {
+ font-size: 12pt;
+ width: 100%;
+ position: relative;
+}
+.prview table tr.mouseover {
+ background-color: #f3f3f3;
+}
+.prview table tr h2 {
+ font-size: 18pt;
+}
+.prview table tr td {
+ width: 100%;
+ height: 100%;
+ line-height: 2;
+ display: flex;
+}
+.prview table tr td.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.prview table tr td.list {
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+ display: flex;
+}
+.prview table tr td.list span {
+ width: 100px;
+ min-height: 100%;
+ display: block;
+}
+.prview table tr td.list > p {
+ display: block;
+ text-align: justify;
+}
+.prview table tr td.list div,
+.prview table tr td.list article {
+ max-width: calc(100% - 100px);
+ white-space: normal;
+}
+.prview table tr td.list div.text-justify,
+.prview table tr td.list article.text-justify {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+}
+.prview table tr.date td > div {
+ width: 100%;
+ text-align: right;
+}
+.prview table tr.date td > div.text-justify {
+ display: flex;
+ justify-content: space-between;
+}
+.prview table td,
+.prview table th {
+ padding: 8px;
+}
+
+main table {
+ border: none;
+ margin-top: 30px;
+ font-family: "標楷體";
+ width: 800px;
+}
+main table tr:nth-child(even),
+main table tr:nth-child(odd) {
+ background-color: #fff;
+}
+main table tr {
+ font-size: 12pt;
+ width: 100%;
+ position: relative;
+}
+main table tr.mouseover {
+ background-color: #ccc;
+}
+main table tr h2 {
+ font-size: 18pt;
+}
+main table tr td {
+ width: 100%;
+ height: 100%;
+ line-height: 2;
+ display: flex;
+}
+main table tr td.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+main table tr td.list {
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+ display: flex;
+}
+main table tr td.list span {
+ width: 60px;
+ min-height: 100%;
+ display: block;
+}
+main table tr td.list > p {
+ display: block;
+ text-align: justify;
+}
+main table tr td.list div {
+ max-width: calc(100% - 60px);
+ white-space: normal;
+}
+main table tr td.list div.text-justify {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+}
+main table tr.date td > div {
+ width: 100%;
+ text-align: right;
+}
+main table tr.date td > div.text-justify {
+ display: flex;
+ justify-content: space-between;
+}
+main table td,
+main table th {
+ padding: 8px;
+}
+
+.prview {
+ width: 800px;
+ margin: 0 auto;
+ border: 1px #ccc solid;
+ padding: 20px;
+ font-family: "標楷體";
+}
+.prview.none {
+ display: none;
+}
+.prview h2 {
+ font-size: 18pt;
+ text-align: center;
+}
+.prview p {
+ font-size: 12pt;
+}
+
+.loader {
+ border: 4px solid #f3f3f3;
+ /* Light grey */
+ border-top: 4px solid #999;
+ /* Blue */
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ animation: spin 2s linear infinite;
+}
+
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+.contract-input-component .form,
+.contract-management .form,
+.contract-new-apply-component .form {
+ margin: 0 auto;
+}
+.contract-input-component .form .dropdown,
+.contract-management .form .dropdown,
+.contract-new-apply-component .form .dropdown {
+ width: 100%;
+ margin-top: 7px;
+}
+.contract-input-component .form .savebtn,
+.contract-management .form .savebtn,
+.contract-new-apply-component .form .savebtn {
+ margin-right: 13px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 70px;
+ height: 45px;
+ font-size: 15px;
+}
+.contract-input-component .form table .fixed,
+.contract-management .form table .fixed,
+.contract-new-apply-component .form table .fixed {
+ padding: 8px 0;
+ cursor: not-allowed;
+}
+.contract-input-component .form table .alerttext,
+.contract-management .form table .alerttext,
+.contract-new-apply-component .form table .alerttext {
+ font-size: 13px;
+ color: #a00;
+ font-weight: 500;
+ margin: 3px;
+ font-weight: 900;
+ padding: 0;
+}
+.contract-input-component .form input[type=file],
+.contract-management .form input[type=file],
+.contract-new-apply-component .form input[type=file] {
+ padding: 12px 20px;
+ margin: 8px 0;
+}
+.contract-input-component .form span,
+.contract-management .form span,
+.contract-new-apply-component .form span {
+ font-weight: 900;
+}
+.contract-input-component .form span.successtext,
+.contract-management .form span.successtext,
+.contract-new-apply-component .form span.successtext {
+ color: #0a0;
+}
+.contract-input-component .form span.failtext,
+.contract-management .form span.failtext,
+.contract-new-apply-component .form span.failtext {
+ color: #a00;
+}
+.contract-input-component .form span.readtext,
+.contract-management .form span.readtext,
+.contract-new-apply-component .form span.readtext {
+ color: #aa0;
+}
+.contract-input-component .form input[type=number]::-webkit-outer-spin-button,
+.contract-input-component .form input[type=number]::-webkit-inner-spin-button,
+.contract-management .form input[type=number]::-webkit-outer-spin-button,
+.contract-management .form input[type=number]::-webkit-inner-spin-button,
+.contract-new-apply-component .form input[type=number]::-webkit-outer-spin-button,
+.contract-new-apply-component .form input[type=number]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+.contract-input-component .form input[type=number],
+.contract-management .form input[type=number],
+.contract-new-apply-component .form input[type=number] {
+ -moz-appearance: textfield;
+}
+.contract-input-component .error,
+.contract-management .error,
+.contract-new-apply-component .error {
+ display: flex;
+ flex-direction: column;
+ margin: 15px;
+}
+.contract-input-component .error .errortext,
+.contract-management .error .errortext,
+.contract-new-apply-component .error .errortext {
+ font-size: 16px;
+ font-weight: 500;
+ color: #a00;
+}
+.contract-input-component .input-group-btn,
+.contract-management .input-group-btn,
+.contract-new-apply-component .input-group-btn {
+ font-size: 16px;
+}
+@media screen and (max-width: 600px) {
+ .contract-input-component table,
+ .contract-management table,
+ .contract-new-apply-component table {
+ border: 0;
+ }
+ .contract-input-component table thead,
+ .contract-management table thead,
+ .contract-new-apply-component table thead {
+ display: none;
+ }
+ .contract-input-component table tr,
+ .contract-management table tr,
+ .contract-new-apply-component table tr {
+ margin-bottom: 10px;
+ display: block;
+ border-bottom: 2px solid #ddd;
+ }
+ .contract-input-component table td,
+ .contract-management table td,
+ .contract-new-apply-component table td {
+ display: block;
+ text-align: left;
+ font-size: 14px;
+ border-bottom: 1px dotted #ccc;
+ }
+ .contract-input-component table td:last-child,
+ .contract-management table td:last-child,
+ .contract-new-apply-component table td:last-child {
+ border-bottom: 0;
+ }
+ .contract-input-component table td:before,
+ .contract-management table td:before,
+ .contract-new-apply-component table td:before {
+ content: attr(data-label);
+ float: left;
+ text-transform: uppercase;
+ font-weight: bold;
+ }
+}
+.contract-input-component .images,
+.contract-management .images,
+.contract-new-apply-component .images {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 20px;
+}
+.contract-input-component .images > .image,
+.contract-management .images > .image,
+.contract-new-apply-component .images > .image {
+ position: relative;
+ margin: 10px;
+}
+.contract-input-component .images > .image:hover > i,
+.contract-management .images > .image:hover > i,
+.contract-new-apply-component .images > .image:hover > i {
+ opacity: 1;
+}
+.contract-input-component .images > .image > i,
+.contract-management .images > .image > i,
+.contract-new-apply-component .images > .image > i {
+ position: absolute;
+ top: -12px;
+ right: -12px;
+ color: #b00;
+ cursor: pointer;
+ opacity: 0;
+ transition: 0.3s;
+}
+
+table {
+ table-layout: fixed;
+ width: 100%;
+}
+
+td {
+ word-wrap: break-word;
+}
+
+img {
+ width: 125px;
+}
+
+.width_style_1 {
+ width: 125px;
+}
+
+table {
+ width: 100%;
+}
+
+#table_index_filter {
+ float: right;
+}
+
+#table_index_paginate {
+ float: right;
+}
+
+label {
+ display: inline-flex;
+ margin-bottom: 0.5rem;
+ margin-top: 0.5rem;
+}/*# sourceMappingURL=style.css.map */
\ No newline at end of file
diff --git a/wms/contract-repair/styles/style.css.map b/wms/contract-repair/styles/style.css.map
new file mode 100644
index 00000000..01c2d24a
--- /dev/null
+++ b/wms/contract-repair/styles/style.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["style.css","style.scss"],"names":[],"mappings":"AAAA,gBAAgB;ACAhB;EAKI,aAAA;EACA,2BAAA;EACA,iBAAA;ADFJ;ACJI;EACI,wBAAA;ADMR;ACCI;EACI,YAAA;EACA,iBAAA;EACA,4BAAA;EACA,4BAAA;EACA,kBAAA;ADCR;ACCQ;EACI,cAAA;EACA,aAAA;EACA,YAAA;EACA,cAAA;EACA,6BAAA;EACA,mBAAA;EACA,6BAAA;EACA,aAAA;ADCZ;ACCY;EACI,UAAA;ADChB;ACEY;EACI,UAAA;ADAhB;ACIQ;EACI,cAAA;EACA,YAAA;EACA,YAAA;EACA,kBAAA;EACA,iBAAA;EACA,qBAAA;EACA,yBAAA;EACA,WAAA;EACA,gBAAA;ADFZ;ACMI;EACI,aAAA;EACA,aAAA;EACA,sBAAA;ADJR;ACMQ;EACI,mBAAA;ADJZ;ACMY;;EAEI,sBAAA;EACA,aAAA;EACA,kBAAA;EACA,YAAA;EACA,YAAA;EACA,eAAA;ADJhB;ACOY;EACI,yBAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,sBAAA;EACA,YAAA;EACA,YAAA;EACA,iBAAA;EACA,gBAAA;ADLhB;ACUI;;EAMI,WAAA;EACA,gBAAA;EACA,iBAAA;EACA,oCAAA;ADZR;ACKQ;;EACI,SAAA;ADFZ;ACUQ;;EACI,aAAA;EACA,mBAAA;ADPZ;ACSY;;EACI,YAAA;EACA,aAAA;ADNhB;ACUQ;;EACI,gBAAA;EACA,WAAA;EACA,gBAAA;EACA,aAAA;EACA,kBAAA;ADPZ;ACSY;;EACI,eAAA;EACA,kBAAA;ADNhB;ACSY;;EACI,gBAAA;ADNhB;ACSY;;EACI,aAAA;EACA,mBAAA;ADNhB;ACSY;;EACI,yBAAA;EACA,eAAA;ADNhB;ACSY;;;;EAEI,eAAA;EACA,gBAAA;ADLhB;ACOgB;;;;EACI,WAAA;EACA,aAAA;EACA,mBAAA;EACA,8BAAA;ADFpB;ACIoB;;;;EACI,iBAAA;ADCxB;ACEoB;;;;EACI,iBAAA;EACA,mBAAA;ADGxB;ACCgB;;;;EACI,iBAAA;ADIpB;ACAgB;;;;EACI,aAAA;EACA,uBAAA;ADKpB;ACHoB;;;;EACI,eAAA;ADQxB;ACHY;;;;;;EAGI,kBAAA;EACA,cAAA;ADQhB;ACHY;;EACI,aAAA;EACA,mBAAA;EACA,WAAA;EACA,iBAAA;ADMhB;ACJgB;;EACI,UAAA;EACA,oBAAA;ADOpB;ACJgB;;EACI,UAAA;EACA,aAAA;EACA,8BAAA;EACA,2BAAA;ADOpB;ACHY;;EACI,kBAAA;EACA,MAAA;EACA,QAAA;EACA,aAAA;EACA,UAAA;ADMhB;ACJgB;;EACI,WAAA;EACA,YAAA;EACA,kBAAA;EACA,UAAA;EACA,aAAA;EACA,uBAAA;EACA,mBAAA;EACA,sBAAA;EACA,aAAA;EACA,WAAA;EACA,aAAA;ADOpB;ACLoB;;EACI,eAAA;ADQxB;ACLoB;;EACI,yBAAA;ADQxB;ACLoB;;EACI,yBAAA;ADQxB;ACLoB;;EACI,gCAAA;ADQxB;ACFQ;;EACI,YAAA;EACA,gBAAA;EACA,kBAAA;EACA,YAAA;ADKZ;ACHY;;;;EAEI,sBAAA;ADOhB;ACJY;;EACI,eAAA;EACA,WAAA;EACA,kBAAA;ADOhB;ACLgB;;EACI,yBAAA;ADQpB;ACLgB;;EACI,eAAA;ADQpB;ACLgB;;EACI,WAAA;EACA,YAAA;EACA,cAAA;EAQA,aAAA;ADCpB;ACPoB;;EACI,aAAA;EACA,uBAAA;EACA,mBAAA;ADUxB;ACLoB;;EACI,WAAA;EACA,YAAA;EACA,mBAAA;EACA,aAAA;ADQxB;ACNwB;;EACI,YAAA;EACA,gBAAA;EACA,cAAA;ADS5B;ACNwB;;EACI,cAAA;EACA,mBAAA;ADS5B;ACNwB;;;;EAEI,6BAAA;EACA,mBAAA;ADU5B;ACR4B;;;;;;;;;;;;EAGI,uBAAA;EACA,wCAAA;EACA,WAAA;EACA,aAAA;EACA,kBAAA;ADmBhC;AChB4B;;;;EACI,aAAA;EACA,WAAA;EACA,8BAAA;ADqBhC;ACXwB;;EACI,WAAA;EACA,iBAAA;ADc5B;ACZ4B;;EACI,aAAA;EACA,8BAAA;ADehC;ACPY;;;;EAEI,YAAA;ADWhB;ACPQ;EACI;IACI,UAAA;EDSd;AACF;ACLI;EACI,eAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;EACA,aAAA;EACA,aAAA;EACA,uBAAA;EACA,mBAAA;EACA,YAAA;EACA,gCAAA;ADOR;ACLQ;EACI,kBAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;EACA,YAAA;EACA,oCAAA;ADOZ;ACJQ;EACI,YAAA;EACA,gBAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,uBAAA;ADMZ;ACJY;EACI,WAAA;EACA,yBAAA;EACA,YAAA;EACA,aAAA;EACA,8BAAA;EACA,mBAAA;EACA,eAAA;ADMhB;ACJgB;EACI,YAAA;EACA,wCAAA;EACA,eAAA;ADMpB;ACJoB;EACI,WAAA;ADMxB;ACFgB;EACI,WAAA;ADIpB;ACAY;EACI,aAAA;ADEhB;ACAgB;EACI,WAAA;EACA,gBAAA;EACA,aAAA;EACA,sBAAA;EACA,aAAA;EACA,kBAAA;ADEpB;ACII;;EAEI,yBAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,sBAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;EACA,kBAAA;EACA,iBAAA;ADFR;ACKI;EACI,yBAAA;ADHR;;ACOA;;EAEI,kBAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,iDAAA;EACA,wBAAA;EACA,eAAA;EACA,mBAAA;ADJJ;ACMI;;EACI,WAAA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;EACA,YAAA;EACA,gBAAA;EACA,kBAAA;EACA,4BAAA;EACA,gBAAA;ADHR;ACMI;;EACI,uDAAA;ADHR;ACKQ;;EACI,UAAA;ADFZ;ACOI;;EACI,WAAA;ADJR;;ACSA;EACI,YAAA;EACA,gBAAA;EACA,kBAAA;EACA,YAAA;EACA,sBAAA;ADNJ;ACQI;;EAEI,sBAAA;ADNR;ACSI;EACI,eAAA;EACA,WAAA;EACA,kBAAA;ADPR;ACSQ;EACI,yBAAA;ADPZ;ACUQ;EACI,eAAA;ADRZ;ACWQ;EACI,WAAA;EACA,YAAA;EACA,cAAA;EAQA,aAAA;ADhBZ;ACUY;EACI,aAAA;EACA,uBAAA;EACA,mBAAA;ADRhB;ACaY;EACI,WAAA;EACA,YAAA;EACA,mBAAA;EACA,aAAA;ADXhB;ACagB;EACI,YAAA;EACA,gBAAA;EACA,cAAA;ADXpB;ACcgB;EACI,cAAA;EACA,mBAAA;ADZpB;ACegB;;EAEI,6BAAA;EACA,mBAAA;ADbpB;ACeoB;;EACI,aAAA;EACA,WAAA;EACA,8BAAA;ADZxB;ACoBgB;EACI,WAAA;EACA,iBAAA;ADlBpB;ACoBoB;EACI,aAAA;EACA,8BAAA;ADlBxB;AC0BI;;EAEI,YAAA;ADxBR;;AC6BI;EACI,YAAA;EACA,gBAAA;EACA,kBAAA;EACA,YAAA;AD1BR;AC4BQ;;EAEI,sBAAA;AD1BZ;AC6BQ;EACI,eAAA;EACA,WAAA;EACA,kBAAA;AD3BZ;AC6BY;EACI,sBAAA;AD3BhB;AC8BY;EACI,eAAA;AD5BhB;AC+BY;EACI,WAAA;EACA,YAAA;EACA,cAAA;EAQA,aAAA;ADpChB;AC8BgB;EACI,aAAA;EACA,uBAAA;EACA,mBAAA;AD5BpB;ACiCgB;EACI,WAAA;EACA,YAAA;EACA,mBAAA;EACA,aAAA;AD/BpB;ACiCoB;EACI,WAAA;EACA,gBAAA;EACA,cAAA;AD/BxB;ACkCoB;EACI,cAAA;EACA,mBAAA;ADhCxB;ACmCoB;EACI,4BAAA;EACA,mBAAA;ADjCxB;ACmCwB;EACI,aAAA;EACA,WAAA;EACA,8BAAA;ADjC5B;AC2CoB;EACI,WAAA;EACA,iBAAA;ADzCxB;AC2CwB;EACI,aAAA;EACA,8BAAA;ADzC5B;ACiDQ;;EAEI,YAAA;AD/CZ;;ACoDA;EACI,YAAA;EACA,cAAA;EACA,sBAAA;EACA,aAAA;EACA,kBAAA;ADjDJ;ACmDI;EACI,aAAA;ADjDR;ACoDI;EACI,eAAA;EACA,kBAAA;ADlDR;ACqDI;EACI,eAAA;ADnDR;;ACuDA;EACI,yBAAA;EACA,eAAA;EACA,0BAAA;EACA,SAAA;EACA,kBAAA;EACA,WAAA;EACA,YAAA;EACA,kCAAA;ADpDJ;;ACuDA;EACI;IACI,uBAAA;EDpDN;ECuDE;IACI,yBAAA;EDrDN;AACF;AC2DI;;;EACI,cAAA;ADvDR;ACyDQ;;;EACI,WAAA;EACA,eAAA;ADrDZ;ACwDQ;;;EACI,kBAAA;EACA,aAAA;EACA,uBAAA;EACA,mBAAA;EACA,WAAA;EACA,YAAA;EACA,eAAA;ADpDZ;ACwDY;;;EACI,cAAA;EACA,mBAAA;ADpDhB;ACuDY;;;EACI,eAAA;EACA,WAAA;EACA,gBAAA;EACA,WAAA;EACA,gBAAA;EACA,UAAA;ADnDhB;ACuDQ;;;EACI,kBAAA;EACA,aAAA;ADnDZ;ACsDQ;;;EACI,gBAAA;ADlDZ;ACoDY;;;EACI,WAAA;ADhDhB;ACmDY;;;EACI,WAAA;AD/ChB;ACkDY;;;EACI,WAAA;AD9ChB;ACkDQ;;;;;;EAEI,wBAAA;EACA,SAAA;AD5CZ;AC+CQ;;;EACI,0BAAA;AD3CZ;AC+CI;;;EACI,aAAA;EACA,sBAAA;EACA,YAAA;AD3CR;AC6CQ;;;EACI,eAAA;EACA,gBAAA;EACA,WAAA;ADzCZ;AC6CI;;;EACI,eAAA;ADzCR;AC4CI;EACI;;;IACI,SAAA;EDxCV;EC2CM;;;IACI,aAAA;EDvCV;EC0CM;;;IACI,mBAAA;IACA,cAAA;IACA,6BAAA;EDtCV;ECyCM;;;IACI,cAAA;IACA,gBAAA;IACA,eAAA;IACA,8BAAA;EDrCV;ECwCM;;;IACI,gBAAA;EDpCV;ECuCM;;;IACI,yBAAA;IACA,WAAA;IACA,yBAAA;IACA,iBAAA;EDnCV;AACF;ACsCI;;;EACI,aAAA;EACA,eAAA;EACA,aAAA;ADlCR;ACoCQ;;;EACI,kBAAA;EACA,YAAA;ADhCZ;ACkCY;;;EACI,UAAA;AD9BhB;ACiCY;;;EACI,kBAAA;EACA,UAAA;EACA,YAAA;EACA,WAAA;EACA,eAAA;EACA,UAAA;EACA,gBAAA;AD7BhB;;ACoCA;EACI,mBAAA;EACA,WAAA;ADjCJ;;ACoCA;EACI,qBAAA;ADjCJ;;ACoCA;EACI,YAAA;ADjCJ;;ACoCA;EACI,YAAA;ADjCJ;;ACoCA;EACI,WAAA;ADjCJ;;ACoCA;EACI,YAAA;ADjCJ;;ACoCA;EACI,YAAA;ADjCJ;;ACoCA;EACI,oBAAA;EACA,qBAAA;EACA,kBAAA;ADjCJ","file":"style.css"}
\ No newline at end of file
diff --git a/wms/contract-repair/styles/style.scss b/wms/contract-repair/styles/style.scss
new file mode 100644
index 00000000..2eabc33d
--- /dev/null
+++ b/wms/contract-repair/styles/style.scss
@@ -0,0 +1,871 @@
+main {
+ [x-cloak] {
+ display: none !important;
+ }
+
+ display: flex;
+ justify-content: flex-start;
+ margin-top: -20px;
+
+ >.sidebar {
+ width: 300px;
+ min-height: 100vh;
+ border-right: 1px #ddd solid;
+ box-shadow: 0px 0px 5px #ddd;
+ padding: 50px 20px;
+
+ button {
+ display: block;
+ outline: none;
+ border: none;
+ color: #1E74FD;
+ background-color: transparent;
+ margin-bottom: 20px;
+ border-bottom: 1px #ccc solid;
+ opacity: .65;
+
+ &.active {
+ opacity: 1;
+ }
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+
+ a {
+ display: block;
+ width: 120px;
+ height: 35px;
+ text-align: center;
+ line-height: 35px;
+ text-decoration: none;
+ background-color: #1E74FD;
+ color: #fff;
+ margin-top: 50px;
+ }
+ }
+
+ .inputDiv {
+ padding: 30px;
+ display: flex;
+ flex-direction: column;
+
+ label {
+ margin-bottom: 10px;
+
+ input,
+ select {
+ border: 1px #aaa solid;
+ outline: none;
+ border-radius: 5px;
+ width: 220px;
+ height: 32px;
+ padding: 0 10px;
+ }
+
+ button {
+ background-color: #1E74FD;
+ color: #fff;
+ outline: none;
+ border: none;
+ border: 1px #ccc solid;
+ width: 220px;
+ height: 32px;
+ font-weight: 6500;
+ margin-top: 15px;
+ }
+ }
+ }
+
+ .contract-install-component,
+ .contract-material-component {
+ p {
+ margin: 0;
+ }
+
+ width: 100%;
+ max-width: 816px;
+ margin:30px auto;
+ background-color: #f7f7f7 !important;
+
+ >.btn-list {
+ display: flex;
+ align-items: center;
+
+ >button {
+ padding: 8px;
+ margin: 0 4px;
+ }
+ }
+
+ >.contract {
+ background: #fff;
+ width: 100%;
+ margin-top: 15px;
+ padding: 20px;
+ font-family: '標楷體';
+
+ >h2 {
+ font-size: 18pt;
+ text-align: center;
+ }
+
+ br {
+ line-height: 2.5;
+ }
+
+ .d-flex {
+ display: flex;
+ align-items: center;
+ }
+
+ .mouseover {
+ background-color: #f1f1f1;
+ cursor: pointer;
+ }
+
+ div,
+ section {
+ font-size: 12pt;
+ line-height: 2.5;
+
+ &.party {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ .company-name {
+ text-indent: 80pt;
+ }
+
+ .notes {
+ margin-right: 25%;
+ white-space: nowrap
+ }
+ }
+
+ &.list-content {
+ margin-left: 70px;
+
+ }
+
+ &.list-title {
+ display: flex;
+ align-items: flex-start;
+
+ >strong {
+ min-width: 70px;
+ }
+ }
+ }
+
+ p,
+ article,
+ div {
+ position: relative;
+ display: block;
+
+
+ }
+
+ .date {
+ display: flex;
+ align-items: center;
+ width: 100%;
+ margin-top: 300px;
+
+ p {
+ width: 50%;
+ letter-spacing: 20px;
+ }
+
+ >.ml {
+ width: 50%;
+ display: flex;
+ justify-content: space-between;
+ flex-direction: row-reverse;
+ }
+ }
+
+ .buttons {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: flex;
+ z-index: 9;
+
+ >button {
+ width: 30px;
+ height: 30px;
+ border-radius: 5px;
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ border: 2px #fff solid;
+ outline: none;
+ color: #fff;
+ margin: 0 1px;
+
+ >i {
+ font-size: 12px;
+ }
+
+ &.edit {
+ background-color: #5BC0DE;
+ }
+
+ &.add {
+ background-color: #F0AD4E;
+ }
+
+ &.delete {
+ background-color: rgb(211, 0, 0);
+ }
+ }
+ }
+ }
+
+ >.contract table {
+ border: none;
+ margin-top: 30px;
+ font-family: '標楷體';
+ width: 800px;
+
+ tr:nth-child(even),
+ tr:nth-child(odd) {
+ background-color: #fff;
+ }
+
+ tr {
+ font-size: 12pt;
+ width: 100%;
+ position: relative;
+
+ &.mouseover {
+ background-color: #f3f3f3;
+ }
+
+ h2 {
+ font-size: 18pt;
+ }
+
+ td {
+ width: 100%;
+ height: 100%;
+ line-height: 2;
+
+ &.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ display: flex;
+
+ &.list {
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+ display: flex;
+
+ span {
+ width: 100px;
+ min-height: 100%;
+ display: block;
+ }
+
+ >p {
+ display: block;
+ text-align: justify;
+ }
+
+ div,
+ article {
+ max-width: calc(100% - 100px);
+ white-space: normal;
+
+ input[type='text'],
+ input[type='number'],
+ input {
+ border: none !important;
+ border-bottom: 1px #222 solid !important;
+ width: 50px;
+ outline: none;
+ text-align: center;
+ }
+
+ &.text-justify {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ }
+ }
+
+ }
+
+ &.date {
+ td {
+ >div {
+ width: 100%;
+ text-align: right;
+
+ &.text-justify {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ }
+ }
+ }
+ }
+
+ td,
+ th {
+ padding: 8px;
+ }
+ }
+
+ @keyframes modelanim {
+ 0% {
+ opacity: 0;
+ }
+ }
+ }
+
+ .contract-model {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+ animation: modelanim .2s linear;
+
+ >.contract-back {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba($color: #000000, $alpha: .5);
+ }
+
+ >.contract-content {
+ z-index: 999;
+ max-width: 600px;
+ width: 100%;
+ border-radius: 6px;
+ overflow: hidden;
+ background-color: rgba($color: #fff, $alpha: 1.0);
+
+ >.model-header {
+ width: 100%;
+ background-color: #1E74FD;
+ height: 38px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 15px;
+
+ >i {
+ float: right;
+ color: #ffffffb4;
+ cursor: pointer;
+
+ &:hover {
+ color: #fff;
+ }
+ }
+
+ >span {
+ color: #fff;
+ }
+ }
+
+ >.content {
+ padding: 30px;
+
+ textarea {
+ width: 100%;
+ resize: vertical;
+ height: 150px;
+ border: 1px #ccc solid;
+ outline: none;
+ border-radius: 6px;
+ }
+ }
+ }
+ }
+
+ .rebtn,
+ .prviewbtn {
+ background-color: #5BC0DE;
+ color: #fff;
+ outline: none;
+ border: none;
+ border: 1px #ccc solid;
+ width: 100px;
+ height: 32px;
+ font-weight: 600;
+ border-radius: 6px;
+ margin-right: 5px;
+ }
+
+ .prviewbtn {
+ background-color: #2E6DA4;
+ }
+}
+
+input[type="checkbox"].scorll,
+input[type="radio"].scorll {
+ position: relative;
+ width: 50px;
+ height: 25px;
+ outline: none;
+ background: linear-gradient(to right, #bbb, #999);
+ -webkit-appearance: none;
+ cursor: pointer;
+ border-radius: 20px;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 25px;
+ height: 25px;
+ background: #fff;
+ border-radius: 50%;
+ transform: scale(0.98, 0.96);
+ transition: .5s;
+ }
+
+ &:checked {
+ background: linear-gradient(to right, #5BC0DE, #2E6DA4);
+
+ &::before {
+ left: 25px;
+ }
+
+ }
+
+ &::after {
+ content: '';
+ }
+
+}
+
+.prview table {
+ border: none;
+ margin-top: 30px;
+ font-family: '標楷體';
+ width: 800px;
+ border: 1px #ccc solid;
+
+ tr:nth-child(even),
+ tr:nth-child(odd) {
+ background-color: #fff;
+ }
+
+ tr {
+ font-size: 12pt;
+ width: 100%;
+ position: relative;
+
+ &.mouseover {
+ background-color: #f3f3f3;
+ }
+
+ h2 {
+ font-size: 18pt;
+ }
+
+ td {
+ width: 100%;
+ height: 100%;
+ line-height: 2;
+
+ &.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ display: flex;
+
+ &.list {
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+ display: flex;
+
+ span {
+ width: 100px;
+ min-height: 100%;
+ display: block;
+ }
+
+ >p {
+ display: block;
+ text-align: justify;
+ }
+
+ div,
+ article {
+ max-width: calc(100% - 100px);
+ white-space: normal;
+
+ &.text-justify {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ }
+ }
+ }
+ }
+
+ &.date {
+ td {
+ >div {
+ width: 100%;
+ text-align: right;
+
+ &.text-justify {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ }
+ }
+ }
+ }
+
+ td,
+ th {
+ padding: 8px;
+ }
+}
+
+main {
+ table {
+ border: none;
+ margin-top: 30px;
+ font-family: '標楷體';
+ width: 800px;
+
+ tr:nth-child(even),
+ tr:nth-child(odd) {
+ background-color: #fff;
+ }
+
+ tr {
+ font-size: 12pt;
+ width: 100%;
+ position: relative;
+
+ &.mouseover {
+ background-color: #ccc;
+ }
+
+ h2 {
+ font-size: 18pt;
+ }
+
+ td {
+ width: 100%;
+ height: 100%;
+ line-height: 2;
+
+ &.center {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+
+ display: flex;
+
+ &.list {
+ width: 100%;
+ height: 100%;
+ white-space: nowrap;
+ display: flex;
+
+ span {
+ width: 60px;
+ min-height: 100%;
+ display: block;
+ }
+
+ >p {
+ display: block;
+ text-align: justify;
+ }
+
+ div {
+ max-width: calc(100% - 60px);
+ white-space: normal;
+
+ &.text-justify {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ }
+ }
+ }
+
+
+ }
+
+ &.date {
+ td {
+ >div {
+ width: 100%;
+ text-align: right;
+
+ &.text-justify {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ }
+ }
+ }
+ }
+
+ td,
+ th {
+ padding: 8px;
+ }
+ }
+}
+
+.prview {
+ width: 800px;
+ margin: 0 auto;
+ border: 1px #ccc solid;
+ padding: 20px;
+ font-family: '標楷體';
+
+ &.none {
+ display: none;
+ }
+
+ h2 {
+ font-size: 18pt;
+ text-align: center;
+ }
+
+ p {
+ font-size: 12pt;
+ }
+}
+
+.loader {
+ border: 4px solid #f3f3f3;
+ /* Light grey */
+ border-top: 4px solid #999;
+ /* Blue */
+ border-radius: 50%;
+ width: 20px;
+ height: 20px;
+ animation: spin 2s linear infinite;
+}
+
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+.contract-input-component,
+.contract-management,
+.contract-new-apply-component {
+ .form {
+ margin: 0 auto;
+
+ .dropdown {
+ width: 100%;
+ margin-top: 7px;
+ }
+
+ .savebtn {
+ margin-right: 13px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 70px;
+ height: 45px;
+ font-size: 15px;
+ }
+
+ table {
+ .fixed {
+ padding: 8px 0;
+ cursor: not-allowed;
+ }
+
+ .alerttext {
+ font-size: 13px;
+ color: #a00;
+ font-weight: 500;
+ margin: 3px;
+ font-weight: 900;
+ padding: 0;
+ }
+ }
+
+ input[type="file"] {
+ padding: 12px 20px;
+ margin: 8px 0;
+ }
+
+ span {
+ font-weight: 900;
+
+ &.successtext {
+ color: #0a0;
+ }
+
+ &.failtext {
+ color: #a00;
+ }
+
+ &.readtext {
+ color: #aa0;
+ }
+ }
+
+ input[type=number]::-webkit-outer-spin-button,
+ input[type=number]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+ }
+
+ input[type=number] {
+ -moz-appearance: textfield;
+ }
+ }
+
+ .error {
+ display: flex;
+ flex-direction: column;
+ margin: 15px;
+
+ .errortext {
+ font-size: 16px;
+ font-weight: 500;
+ color: #a00;
+ }
+ }
+
+ .input-group-btn {
+ font-size: 16px;
+ }
+
+ @media screen and (max-width: 600px) {
+ table {
+ border: 0;
+ }
+
+ table thead {
+ display: none;
+ }
+
+ table tr {
+ margin-bottom: 10px;
+ display: block;
+ border-bottom: 2px solid #ddd;
+ }
+
+ table td {
+ display: block;
+ text-align: left;
+ font-size: 14px;
+ border-bottom: 1px dotted #ccc;
+ }
+
+ table td:last-child {
+ border-bottom: 0;
+ }
+
+ table td:before {
+ content: attr(data-label);
+ float: left;
+ text-transform: uppercase;
+ font-weight: bold;
+ }
+ }
+
+ .images {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 20px;
+
+ >.image {
+ position: relative;
+ margin: 10px;
+
+ &:hover>i {
+ opacity: 1;
+ }
+
+ >i {
+ position: absolute;
+ top: -12px;
+ right: -12px;
+ color: #b00;
+ cursor: pointer;
+ opacity: 0;
+ transition: .3s;
+ }
+ }
+
+ }
+}
+
+table {
+ table-layout: fixed;
+ width: 100%;
+}
+
+td {
+ word-wrap: break-word;
+}
+
+img {
+ width: 125px;
+}
+
+.width_style_1 {
+ width: 125px;
+}
+
+table {
+ width: 100%;
+}
+
+#table_index_filter {
+ float: right;
+}
+
+#table_index_paginate {
+ float: right;
+}
+
+label {
+ display: inline-flex;
+ margin-bottom: .5rem;
+ margin-top: .5rem;
+}
\ No newline at end of file
diff --git a/wms/contract-user-input.php b/wms/contract-user-input.php
index a9afa2f8..99d39bae 100644
--- a/wms/contract-user-input.php
+++ b/wms/contract-user-input.php
@@ -1,63 +1,63 @@
-
+
diff --git a/wms/contract/api/getContractData.php b/wms/contract/api/getContractData.php
index df52d1dd..0f7f89c8 100644
--- a/wms/contract/api/getContractData.php
+++ b/wms/contract/api/getContractData.php
@@ -57,4 +57,6 @@ if(isset($_GET['contractno']) && $_GET['contractno']!='' && isset($_GET['contrac
}catch (PDOException $e ){
die("ERROR!!!: ". $e->getMessage());
}
-}
\ No newline at end of file
+}
+
+
diff --git a/wms/contract/api/postContractData.php b/wms/contract/api/postContractData.php
index 69e7d859..349557ee 100644
--- a/wms/contract/api/postContractData.php
+++ b/wms/contract/api/postContractData.php
@@ -1,319 +1,317 @@
- 0) {
- header("HTTP/1.1 422 Unprocessable Entity");
- echo json_encode($fail_arr);
- exit();
- }
-
- //create account table
- $accounttype = "A";
- $accountid = $vat;
- $pwd = "123";
- $name = $partyA;
- $tel = $phone ?? '';
- $repairerid = $mworker;
- $creater = $user_id;
- $create_at = date('Y-m-d H:i:s');
-
- $conn->beginTransaction();
-
- $sql_str = "INSERT INTO account (accounttype, accountid, pwd, name, tel, address, email, repairerid, creater, create_at) VALUES (:accounttype, :accountid, :pwd, :name, :tel, :address, :email, :repairerid, :creater, :create_at)";
- $stmt = $conn -> prepare($sql_str);
- $stmt -> bindParam(':accounttype' ,$accounttype);
- $stmt -> bindParam(':accountid' ,$accountid);
- $stmt -> bindParam(':pwd' ,$pwd);
- $stmt -> bindParam(':name' ,$name);
- $stmt -> bindParam(':tel' ,$tel);
- $stmt -> bindParam(':address' ,$address);
- $stmt -> bindParam(':email' ,$email);
- $stmt -> bindParam(':repairerid' ,$repairerid);
- $stmt -> bindParam(':creater' ,$creater);
- $stmt -> bindParam(':create_at' ,$create_at);
- $stmt -> execute();
-
- //create contract table
-
- $contracttype = $mtype;
- $company = $partyA;
- $taxid = $vat;
- $tel = $phone;
- $promiser = $partyA;
- $contractperson = $partyA;
-
- $contractaddress = $address;
- $contracttel = $phone;
- $contractemail = $email;
- $contract_employee = $salesman;
- $start_date = $contract_begin_date;
- $end_date = $contract_end_date;
-
- $sql_str = "INSERT INTO contract (contracttype, contractno, company, taxid, address, tel, promiser, contractperson, contractaddress, contracttel, contractemail, contract_employee, start_date, end_date, creater, create_at) VALUES (:contracttype, :contractno, :company, :taxid, :address, :tel, :promiser, :contractperson, :contractaddress, :contracttel, :contractemail, :contract_employee, :start_date, :end_date, :creater, :create_at)";
- $stmt = $conn -> prepare($sql_str);
- $stmt -> bindParam(':contracttype' ,$contracttype);
- $stmt -> bindParam(':contractno' ,$contractno);
- $stmt -> bindParam(':company' ,$company);
- $stmt -> bindParam(':taxid' ,$taxid);
- $stmt -> bindParam(':address' ,$address);
- $stmt -> bindParam(':tel' ,$tel);
- $stmt -> bindParam(':promiser' ,$promiser);
- $stmt -> bindParam(':contractperson' ,$contractperson);
- $stmt -> bindParam(':contractaddress' ,$contractaddress);
- $stmt -> bindParam(':contracttel' ,$contracttel);
- $stmt -> bindParam(':contractemail' ,$contractemail);
- $stmt -> bindParam(':contract_employee' ,$contract_employee);
- $stmt -> bindParam(':start_date' ,$start_date);
- $stmt -> bindParam(':end_date' ,$end_date);
- $stmt -> bindParam(':creater' ,$creater);
- $stmt -> bindParam(':create_at' ,$create_at);
- $stmt -> execute();
-
- //create facility table
- $createFacilityNo = new CreateFacilityNo();
- $dailyNecessities = [
- 'MAE100'=>'X',
- 'MAM200'=>'W',
- 'MAH100'=>'H',
- 'MAQ100'=>'Z',
- 'MAF100'=>'F',
- 'MAZ100'=>'B',
- ];
- $facility_arr = [];
- foreach($elevators as $elevator){
- $facility_arr[] = $dailyNecessities[$elevator['spec']];
- }
- echo json_encode($facility_arr);
- $facilityno = $createFacilityNo->makeBFacilityNo("T", $facility_arr, (int)$num);
- echo json_encode($facilityno);
- echo '-------';
- $sql_str = "SELECT accountid, name FROM account WHERE accountid = :accountid";
- $stmt = $conn->prepare($sql_str);
- $stmt->bindParam(':accountid',$mworker);
- $stmt->execute();
- $worker = $stmt->fetch(PDO::FETCH_ASSOC);
- $customerid = $vat;
- $define = "B";
- $repairtype = $mtype;
- $repairerid = $mworker;
- $repairername = $worker['name'];
- foreach($elevators as $idx=>$elevator){
- $sql_str = "INSERT INTO facility (contractno, define, facilityno, latitude, longitude, customerid, weight, numberofpassenger, numberofstop, numberoffloor, opentype, speed, repairtype, maintainance, facility_kind, address, repairerid, repairername, creater, create_at, area, takecertificatedate, licensedate)
- VALUES (:contractno, :define, :facilityno, :latitude, :longitude, :customerid, :weight, :numberofpassenger, :numberofstop, :numberoffloor, :opentype, :speed, :repairtype, :maintainance, :facility_kind, :address, :repairerid, :repairername, :creater, :create_at, :area, :takecertificatedate, :licensedate)";
- $stmt = $conn -> prepare($sql_str);
- $stmt -> bindParam(':contractno' ,$contractno);
- $stmt -> bindParam(':define' ,$define);
- $stmt -> bindParam(':facilityno' ,$facilityno[$idx]);
- $stmt -> bindParam(':latitude' ,$elevator['latitude']);
- $stmt -> bindParam(':longitude' ,$elevator['longitude']);
- $stmt -> bindParam(':customerid' ,$customerid);
- $stmt -> bindParam(':weight' ,$elevator['weight']);
- $stmt -> bindParam(':numberofpassenger' ,$elevator['persons']);
- $stmt -> bindParam(':numberofstop' ,$elevator['stop']);
- $stmt -> bindParam(':numberoffloor' ,$elevator['floors']);
- $stmt -> bindParam(':opentype' ,$elevator['opendoor']);
- $stmt -> bindParam(':speed' ,$elevator['speed']);
- $stmt -> bindParam(':repairtype' ,$repairtype);
- $stmt -> bindParam(':maintainance' ,$elevator['maintainance']);
- $stmt -> bindParam(':facility_kind' ,$elevator['spec']);
- $stmt -> bindParam(':address' ,$address);
- $stmt -> bindParam(':repairerid' ,$repairerid);
- $stmt -> bindParam(':repairername' ,$repairername);
- $stmt -> bindParam(':creater' ,$creater);
- $stmt -> bindParam(':create_at' ,$create_at);
- $stmt -> bindParam(':area' ,$area);
- $stmt -> bindParam(':takecertificatedate' ,$elevator['takecertificatedate']);
- $stmt -> bindParam(':licensedate' ,$elevator['useful_date']);
- $result = $stmt -> execute();
- }
-
- //create schedule table
-
- $comboNo = new CreateComboNo($mcycle, $contract_begin_date, $contract_end_date);
- $comboArr = json_decode($comboNo->getComboNo(), true);
- foreach($facilityno as $no){
- foreach($comboArr as $combo){
- $sql_str = 'INSERT INTO schedule (contractno, facilityno, combono, repairerid, repairername, duedate, creater, create_at) VALUES (:contractno, :facilityno, :combono, :repairerid, :repairername, :duedate, :creater, :create_at)';
- $stmt = $conn -> prepare($sql_str);
- $stmt -> bindParam(':contractno' ,$contractno);
- $stmt -> bindParam(':facilityno' ,$no);
- $stmt -> bindParam(':combono' ,$combo[0]);
- $stmt -> bindParam(':repairerid' ,$repairerid);
- $stmt -> bindParam(':repairername' ,$repairername);
- $stmt -> bindParam(':duedate' ,$combo[1]);
- $stmt -> bindParam(':creater' ,$creater);
- $stmt -> bindParam(':create_at' ,$create_at);
- $result = $stmt -> execute();
- }
- }
- // create contract_b_signed_back table
- $contract_type = $mtype;
- $company = $customer;
- $customer_no = $vat;
- $salesperson = $salesman;
- $customer_phone = $phone;
- $customer_email = $email;
- $repairman = $mworker;
- $cycle = $mcycle;
- $contact_person = $partyA;
- $contact_address = $partyAaddress;
- $contact_phone = $partyAphone;
- $contract_email = $partyAemail;
- $elevators_number = $num;
- $bonus = 1000;
- $max_bonus = 2000;
-
- if(!empty($files)){
- $englisharr = range('a', 'z');
- $file = $_FILES['files'];
- $file_name = $file['name'];
- $file_type = $file['type'];
- $tmp_name = $file['tmp_name'];
- $file_size = $file['size'];
- $error = $file['error'];
- $newfiles = [];
- foreach( $files as $file ){
- $i = 0; //新陣列的索引編號
- foreach( $file as $key => $val ){
- $newfiles[$i]['name'] = $files['name'][$key];
- $newfiles[$i]['type'] = $files['type'][$key];
- $newfiles[$i]['tmp_name'] = $files['tmp_name'][$key];
- $newfiles[$i]['error'] = $files['error'][$key];
- $newfiles[$i]['size'] = $files['size'][$key];
- $i++;
- } //foreach 第2層 end
- }
- $max_size = 4096*4096; //設定允許上傳檔案容量的最大值(1M)
- $allow_ext = array('jpeg', 'jpg', 'png','JPG','JPEG','PNG','GIF'); //設定允許上傳檔案的類型
- $path = '../images/contracts/';
- if (!file_exists($path)) { mkdir($path); }
- $msg_result = ''; //負責接收所有檔案檢測後的回傳訊息
- $datetime = (string)date('YmdHis');
- $files_id = 'b' . $datetime; // 保養=>b + 日期時間
- foreach( $newfiles as $key => $file ){
- $randNum = rand(1000,9999);
- $randEnglish = $englisharr[rand(0,25)];
- $file_name = 'b' . (string)date('YmdHis') . $randNum . $randEnglish . $randNum.$file['name'];
- $msg = upload_chk( $file,$path, $max_size, $allow_ext, $file_name );
- if($msg==1){
- $msg = '檔案傳送成功!';
- $sql_str = "INSERT INTO contract_back_files (files_id, file_name, file_mime, file_size, created_at, created_by) VALUES (:files_id, :file_name, :file_mime, :file_size, :created_at, :created_by)";
- $stmt = $conn -> prepare($sql_str);
- $stmt -> bindParam(':files_id' ,$files_id);
- $stmt -> bindParam(':file_name' ,$file_name);
- $stmt -> bindParam(':file_mime' ,$file['type']);
- $stmt -> bindParam(':file_size' ,$file['size']);
- $stmt -> bindParam(':created_at' ,$created_at);
- $stmt -> bindParam(':created_by' ,$user_id);
- $stmt ->execute();
- }
- $msg_result .= '第' . ($key+1) . '個上傳檔案的結果:' . $msg . ' ';
- $src_name = $path.$file['name'];
- if( file_exists($src_name) ){
- //副檔名
- $extname = pathinfo($src_name, PATHINFO_EXTENSION);
- //主檔名
- $basename = basename($src_name, '.'.$extname);
- }
-
- }
- }else{
- $files = null;
- }
- $sql_str = "INSERT INTO contract_b_signed_back (contract_no, contract_type, company, customer_no, salesperson, contract_start_date, contract_end_date, total_price, customer_phone, customer_email, repairman, cycle, contact_person, contact_address, contact_phone, contact_email, elevators_number, area, address, files_id, bonus, max_bonus, created_at, created_by)
- VALUES (:contract_no, :contract_type, :company, :customer_no, :salesperson, :contract_start_date, :contract_end_date, :total_price, :customer_phone, :customer_email, :repairman, :cycle, :contact_person, :contact_address, :contact_phone, :contact_email, :elevators_number, :area, :address, :files_id, :bonus, :max_bonus, :created_at, :created_by)";
- $stmt = $conn -> prepare($sql_str);
- $stmt -> bindParam(":contract_no",$contractno);
- $stmt -> bindParam(":contract_type",$contract_type);
- $stmt -> bindParam(":company",$company);
- $stmt -> bindParam(":customer_no",$customer_no);
- $stmt -> bindParam(":salesperson",$salesperson);
- $stmt -> bindParam(":contract_start_date",$contract_begin_date);
- $stmt -> bindParam(":contract_end_date",$contract_end_date);
- $stmt -> bindParam(":total_price",$total_price);
- $stmt -> bindParam(":customer_phone",$customer_phone);
- $stmt -> bindParam(":customer_email",$customer_email);
- $stmt -> bindParam(":repairman",$repairman);
- $stmt -> bindParam(":cycle",$cycle);
- $stmt -> bindParam(":contact_person",$contact_person);
- $stmt -> bindParam(":contact_address",$contact_address);
- $stmt -> bindParam(":contact_phone",$contact_phone);
- $stmt -> bindParam(":contact_email",$contact_email);
- $stmt -> bindParam(":elevators_number",$elevators_number);
- $stmt -> bindParam(":area",$area);
- $stmt -> bindParam(":address",$address);
- $stmt -> bindParam(":files_id",$files_id);
- $stmt -> bindParam(":bonus",$bonus);
- $stmt -> bindParam(":max_bonus",$max_bonus);
- $stmt -> bindParam(":created_at", $created_at);
- $stmt -> bindParam(":created_by",$user_id);
-
- $stmt -> execute();
-
- header('Content-Type: application/json');
- $jsonData = json_encode($files);
-
- $conn->commit();
- }catch(PDOException $e){
- $conn->rollback();
- echo $e->getMessage();
- die('Error!:'.$e->getMessage());
- }
-}
-
-
-
-
+ 0) {
+ header("HTTP/1.1 422 Unprocessable Entity");
+ echo json_encode($fail_arr);
+ exit();
+ }
+
+ //create account table
+ $accounttype = "A";
+ $accountid = $vat;
+ $pwd = "123";
+ $name = $partyA;
+ $tel = $phone ?? '';
+ $repairerid = $mworker;
+ $creater = $user_id;
+ $create_at = date('Y-m-d H:i:s');
+
+ $conn->beginTransaction();
+
+ $sql_str = "INSERT INTO account (accounttype, accountid, pwd, name, tel, address, email, repairerid, creater, create_at) VALUES (:accounttype, :accountid, :pwd, :name, :tel, :address, :email, :repairerid, :creater, :create_at)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':accounttype', $accounttype);
+ $stmt->bindParam(':accountid', $accountid);
+ $stmt->bindParam(':pwd', $pwd);
+ $stmt->bindParam(':name', $name);
+ $stmt->bindParam(':tel', $tel);
+ $stmt->bindParam(':address', $address);
+ $stmt->bindParam(':email', $email);
+ $stmt->bindParam(':repairerid', $repairerid);
+ $stmt->bindParam(':creater', $creater);
+ $stmt->bindParam(':create_at', $create_at);
+ $stmt->execute();
+
+ //create contract table
+
+ $contracttype = $mtype;
+ $company = $partyA;
+ $taxid = $vat;
+ $tel = $phone;
+ $promiser = $partyA;
+ $contractperson = $partyA;
+
+ $contractaddress = $address;
+ $contracttel = $phone;
+ $contractemail = $email;
+ $contract_employee = $salesman;
+ $start_date = $contract_begin_date;
+ $end_date = $contract_end_date;
+
+ $sql_str = "INSERT INTO contract (contracttype, contractno, company, taxid, address, tel, promiser, contractperson, contractaddress, contracttel, contractemail, contract_employee, start_date, end_date, creater, create_at) VALUES (:contracttype, :contractno, :company, :taxid, :address, :tel, :promiser, :contractperson, :contractaddress, :contracttel, :contractemail, :contract_employee, :start_date, :end_date, :creater, :create_at)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':contracttype', $contracttype);
+ $stmt->bindParam(':contractno', $contractno);
+ $stmt->bindParam(':company', $company);
+ $stmt->bindParam(':taxid', $taxid);
+ $stmt->bindParam(':address', $address);
+ $stmt->bindParam(':tel', $tel);
+ $stmt->bindParam(':promiser', $promiser);
+ $stmt->bindParam(':contractperson', $contractperson);
+ $stmt->bindParam(':contractaddress', $contractaddress);
+ $stmt->bindParam(':contracttel', $contracttel);
+ $stmt->bindParam(':contractemail', $contractemail);
+ $stmt->bindParam(':contract_employee', $contract_employee);
+ $stmt->bindParam(':start_date', $start_date);
+ $stmt->bindParam(':end_date', $end_date);
+ $stmt->bindParam(':creater', $creater);
+ $stmt->bindParam(':create_at', $create_at);
+ $stmt->execute();
+
+ //create facility table
+ $createFacilityNo = new CreateFacilityNo();
+ $dailyNecessities = [
+ 'MAE100' => 'X',
+ 'MAM200' => 'W',
+ 'MAH100' => 'H',
+ 'MAQ100' => 'Z',
+ 'MAF100' => 'F',
+ 'MAZ100' => 'B',
+ ];
+ $facility_arr = [];
+ foreach ($elevators as $elevator) {
+ $facility_arr[] = $dailyNecessities[$elevator['spec']];
+ }
+ echo json_encode($facility_arr);
+ $facilityno = $createFacilityNo->makeBFacilityNo("T", $facility_arr, (int)$num);
+ echo json_encode($facilityno);
+ echo '-------';
+ $sql_str = "SELECT accountid, name FROM account WHERE accountid = :accountid";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':accountid', $mworker);
+ $stmt->execute();
+ $worker = $stmt->fetch(PDO::FETCH_ASSOC);
+ $customerid = $vat;
+ $define = "B";
+ $repairtype = $mtype;
+ $repairerid = $mworker;
+ $repairername = $worker['name'];
+ foreach ($elevators as $idx => $elevator) {
+ $sql_str = "INSERT INTO facility (contractno, define, facilityno, latitude, longitude, customerid, weight, numberofpassenger, numberofstop, numberoffloor, opentype, speed, repairtype, maintainance, facility_kind, address, repairerid, repairername, creater, create_at, area, takecertificatedate, licensedate)
+ VALUES (:contractno, :define, :facilityno, :latitude, :longitude, :customerid, :weight, :numberofpassenger, :numberofstop, :numberoffloor, :opentype, :speed, :repairtype, :maintainance, :facility_kind, :address, :repairerid, :repairername, :creater, :create_at, :area, :takecertificatedate, :licensedate)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':contractno', $contractno);
+ $stmt->bindParam(':define', $define);
+ $stmt->bindParam(':facilityno', $facilityno[$idx]);
+ $stmt->bindParam(':latitude', $elevator['latitude']);
+ $stmt->bindParam(':longitude', $elevator['longitude']);
+ $stmt->bindParam(':customerid', $customerid);
+ $stmt->bindParam(':weight', $elevator['weight']);
+ $stmt->bindParam(':numberofpassenger', $elevator['persons']);
+ $stmt->bindParam(':numberofstop', $elevator['stop']);
+ $stmt->bindParam(':numberoffloor', $elevator['floors']);
+ $stmt->bindParam(':opentype', $elevator['opendoor']);
+ $stmt->bindParam(':speed', $elevator['speed']);
+ $stmt->bindParam(':repairtype', $repairtype);
+ $stmt->bindParam(':maintainance', $elevator['maintainance']);
+ $stmt->bindParam(':facility_kind', $elevator['spec']);
+ $stmt->bindParam(':address', $address);
+ $stmt->bindParam(':repairerid', $repairerid);
+ $stmt->bindParam(':repairername', $repairername);
+ $stmt->bindParam(':creater', $creater);
+ $stmt->bindParam(':create_at', $create_at);
+ $stmt->bindParam(':area', $area);
+ $stmt->bindParam(':takecertificatedate', $elevator['takecertificatedate']);
+ $stmt->bindParam(':licensedate', $elevator['useful_date']);
+ $result = $stmt->execute();
+ }
+
+ //create schedule table
+
+ $comboNo = new CreateComboNo($mcycle, $contract_begin_date, $contract_end_date);
+ $comboArr = json_decode($comboNo->getComboNo(), true);
+ foreach ($facilityno as $no) {
+ foreach ($comboArr as $combo) {
+ $sql_str = 'INSERT INTO schedule (contractno, facilityno, combono, repairerid, repairername, duedate, creater, create_at) VALUES (:contractno, :facilityno, :combono, :repairerid, :repairername, :duedate, :creater, :create_at)';
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':contractno', $contractno);
+ $stmt->bindParam(':facilityno', $no);
+ $stmt->bindParam(':combono', $combo[0]);
+ $stmt->bindParam(':repairerid', $repairerid);
+ $stmt->bindParam(':repairername', $repairername);
+ $stmt->bindParam(':duedate', $combo[1]);
+ $stmt->bindParam(':creater', $creater);
+ $stmt->bindParam(':create_at', $create_at);
+ $result = $stmt->execute();
+ }
+ }
+ // create contract_b_signed_back table
+ $contract_type = $mtype;
+ $company = $customer;
+ $customer_no = $vat;
+ $salesperson = $salesman;
+ $customer_phone = $phone;
+ $customer_email = $email;
+ $repairman = $mworker;
+ $cycle = $mcycle;
+ $contact_person = $partyA;
+ $contact_address = $partyAaddress;
+ $contact_phone = $partyAphone;
+ $contract_email = $partyAemail;
+ $elevators_number = $num;
+ $bonus = 1000;
+ $max_bonus = 2000;
+
+ if (!empty($files)) {
+ $englisharr = range('a', 'z');
+ $file = $_FILES['files'];
+ $file_name = $file['name'];
+ $file_type = $file['type'];
+ $tmp_name = $file['tmp_name'];
+ $file_size = $file['size'];
+ $error = $file['error'];
+ $newfiles = [];
+ foreach ($files as $file) {
+ $i = 0; //新陣列的索引編號
+ foreach ($file as $key => $val) {
+ $newfiles[$i]['name'] = $files['name'][$key];
+ $newfiles[$i]['type'] = $files['type'][$key];
+ $newfiles[$i]['tmp_name'] = $files['tmp_name'][$key];
+ $newfiles[$i]['error'] = $files['error'][$key];
+ $newfiles[$i]['size'] = $files['size'][$key];
+ $i++;
+ } //foreach 第2層 end
+ }
+ $max_size = 4096 * 4096; //設定允許上傳檔案容量的最大值(1M)
+ $allow_ext = array('jpeg', 'jpg', 'png', 'JPG', 'JPEG', 'PNG', 'GIF'); //設定允許上傳檔案的類型
+ $path = '../images/contracts/';
+ if (!file_exists($path)) {
+ mkdir($path);
+ }
+ $msg_result = ''; //負責接收所有檔案檢測後的回傳訊息
+ $datetime = (string)date('YmdHis');
+ $files_id = 'b' . $datetime; // 保養=>b + 日期時間
+ foreach ($newfiles as $key => $file) {
+ $randNum = rand(1000, 9999);
+ $randEnglish = $englisharr[rand(0, 25)];
+ $file_name = 'b' . (string)date('YmdHis') . $randNum . $randEnglish . $randNum . $file['name'];
+ $msg = upload_chk($file, $path, $max_size, $allow_ext, $file_name);
+ if ($msg == 1) {
+ $msg = '檔案傳送成功!';
+ $sql_str = "INSERT INTO contract_back_files (files_id, file_name, file_mime, file_size, created_at, created_by) VALUES (:files_id, :file_name, :file_mime, :file_size, :created_at, :created_by)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':files_id', $files_id);
+ $stmt->bindParam(':file_name', $file_name);
+ $stmt->bindParam(':file_mime', $file['type']);
+ $stmt->bindParam(':file_size', $file['size']);
+ $stmt->bindParam(':created_at', $created_at);
+ $stmt->bindParam(':created_by', $user_id);
+ $stmt->execute();
+ }
+ $msg_result .= '第' . ($key + 1) . '個上傳檔案的結果:' . $msg . ' ';
+ $src_name = $path . $file['name'];
+ if (file_exists($src_name)) {
+ //副檔名
+ $extname = pathinfo($src_name, PATHINFO_EXTENSION);
+ //主檔名
+ $basename = basename($src_name, '.' . $extname);
+ }
+ }
+ } else {
+ $files = null;
+ }
+ $sql_str = "INSERT INTO contract_b_signed_back (contract_no, contract_type, company, customer_no, salesperson, contract_start_date, contract_end_date, total_price, customer_phone, customer_email, repairman, cycle, contact_person, contact_address, contact_phone, contact_email, elevators_number, area, address, files_id, bonus, max_bonus, created_at, created_by)
+ VALUES (:contract_no, :contract_type, :company, :customer_no, :salesperson, :contract_start_date, :contract_end_date, :total_price, :customer_phone, :customer_email, :repairman, :cycle, :contact_person, :contact_address, :contact_phone, :contact_email, :elevators_number, :area, :address, :files_id, :bonus, :max_bonus, :created_at, :created_by)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(":contract_no", $contractno);
+ $stmt->bindParam(":contract_type", $contract_type);
+ $stmt->bindParam(":company", $company);
+ $stmt->bindParam(":customer_no", $customer_no);
+ $stmt->bindParam(":salesperson", $salesperson);
+ $stmt->bindParam(":contract_start_date", $contract_begin_date);
+ $stmt->bindParam(":contract_end_date", $contract_end_date);
+ $stmt->bindParam(":total_price", $total_price);
+ $stmt->bindParam(":customer_phone", $customer_phone);
+ $stmt->bindParam(":customer_email", $customer_email);
+ $stmt->bindParam(":repairman", $repairman);
+ $stmt->bindParam(":cycle", $cycle);
+ $stmt->bindParam(":contact_person", $contact_person);
+ $stmt->bindParam(":contact_address", $contact_address);
+ $stmt->bindParam(":contact_phone", $contact_phone);
+ $stmt->bindParam(":contact_email", $contact_email);
+ $stmt->bindParam(":elevators_number", $elevators_number);
+ $stmt->bindParam(":area", $area);
+ $stmt->bindParam(":address", $address);
+ $stmt->bindParam(":files_id", $files_id);
+ $stmt->bindParam(":bonus", $bonus);
+ $stmt->bindParam(":max_bonus", $max_bonus);
+ $stmt->bindParam(":created_at", $created_at);
+ $stmt->bindParam(":created_by", $user_id);
+
+ $stmt->execute();
+
+ header('Content-Type: application/json');
+ $jsonData = json_encode($files);
+
+ $conn->commit();
+ } catch (PDOException $e) {
+ $conn->rollback();
+ http_response_code(404);
+ echo $e->getMessage();
+ die('Error!:' . $e->getMessage());
+ }
+}
diff --git a/wms/contract/api/postContractNewApplyData.php b/wms/contract/api/postContractNewApplyData.php
index a3930586..e5b500fb 100644
--- a/wms/contract/api/postContractNewApplyData.php
+++ b/wms/contract/api/postContractNewApplyData.php
@@ -1,11 +1,17 @@
beginTransaction();
- try{
- if($isFirst == 1){
- $sql_str = "INSERT INTO contract_new_apply (mid, contractno, sales_man, apply_date, apply_type, case_name, customer, manager, vat, total_price, buy_fee, install_fee, contact_address, workdeadline_a, workdeadline_b, test_time, freedeadline, trade_address, tradedeadline, secondPayDeadline, progress, status, person, personname, submit_date, created_at, created_by) VALUES (:mid, :contractno, :sales_man, :apply_date, :apply_type, :case_name, :customer, :manager, :vat, :total_price, :buy_fee, :install_fee, :contact_address, :workdeadline_a, :workdeadline_b, :test_time, :freedeadline, :trade_address, :tradedeadline, :secondPayDeadline, :progress, :status, :person, :personname, :submit_date, :created_at, :created_by)";
- $stmt = $conn -> prepare($sql_str);
- $stmt ->bindParam(':mid', $mid);
- $stmt ->bindParam(':contractno', $vol_no);
- $stmt ->bindParam(':sales_man', $salesman);
- $stmt ->bindParam(':apply_date', $apply_date);
- $stmt ->bindParam(':apply_type', $apply_type);
- $stmt ->bindParam(':case_name', $case_name);
- $stmt ->bindParam(':customer', $customer);
- $stmt ->bindParam(':manager', $manager);
- $stmt ->bindParam(':vat', $vat);
- $stmt ->bindParam(':total_price', $total_price);
- $stmt ->bindParam(':buy_fee', $buy_fee);
- $stmt ->bindParam(':install_fee', $install_fee);
- $stmt ->bindParam(':contact_address', $contact_address);
- $stmt ->bindParam(':workdeadline_a', $workdeadline_a);
- $stmt ->bindParam(':workdeadline_b', $workdeadline_b);
- $stmt ->bindParam(':test_time', $test_time);
- $stmt ->bindParam(':freedeadline', $freedeadline);
- $stmt ->bindParam(':trade_address', $trade_address);
- $stmt ->bindParam(':tradedeadline', $tradedeadline);
- $stmt ->bindParam(':secondPayDeadline', $secondPayDeadline);
- $stmt ->bindParam(':progress', $progress);
- $stmt ->bindParam(':status', $status);
- $stmt ->bindParam(':person', $salesman);
- $stmt ->bindParam(':personname', $salesmanname);
- $stmt ->bindParam(':submit_date', $submit_date);
- $stmt ->bindParam(':created_at', $created_at);
- $stmt ->bindParam(':created_by', $created_by);
- $stmt ->execute();
+ try {
+ if ($isFirst == 1) {
+ $sql_str = "INSERT INTO contract_new_apply (mid, contractno, sales_man, apply_date, apply_type, case_name, customer, manager, vat, total_price, total_items, buy_fee, install_fee, contact_address, workdeadline_a, workdeadline_b, test_time, freedeadline, trade_address, tradedeadline, secondPayDeadline, progress, status, person, personname, submit_date, created_at, created_by) VALUES (:mid, :contractno, :sales_man, :apply_date, :apply_type, :case_name, :customer, :manager, :vat, :total_price, :total_items, :buy_fee, :install_fee, :contact_address, :workdeadline_a, :workdeadline_b, :test_time, :freedeadline, :trade_address, :tradedeadline, :secondPayDeadline, :progress, :status, :person, :personname, :submit_date, :created_at, :created_by)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':mid', $mid);
+ $stmt->bindParam(':contractno', $vol_no);
+ $stmt->bindParam(':sales_man', $salesman);
+ $stmt->bindParam(':apply_date', $apply_date);
+ $stmt->bindParam(':apply_type', $apply_type);
+ $stmt->bindParam(':case_name', $case_name);
+ $stmt->bindParam(':customer', $customer);
+ $stmt->bindParam(':manager', $manager);
+ $stmt->bindParam(':vat', $vat);
+ $stmt->bindParam(':total_price', $total_price);
+ $stmt->bindParam(':total_items', $total_items);
+ $stmt->bindParam(':buy_fee', $buy_fee);
+ $stmt->bindParam(':install_fee', $install_fee);
+ $stmt->bindParam(':contact_address', $contact_address);
+ $stmt->bindParam(':workdeadline_a', $workdeadline_a);
+ $stmt->bindParam(':workdeadline_b', $workdeadline_b);
+ $stmt->bindParam(':test_time', $test_time);
+ $stmt->bindParam(':freedeadline', $freedeadline);
+ $stmt->bindParam(':trade_address', $trade_address);
+ $stmt->bindParam(':tradedeadline', $tradedeadline);
+ $stmt->bindParam(':secondPayDeadline', $secondPayDeadline);
+ $stmt->bindParam(':progress', $progress);
+ $stmt->bindParam(':status', $status);
+ $stmt->bindParam(':person', $salesman);
+ $stmt->bindParam(':personname', $salesmanname);
+ $stmt->bindParam(':submit_date', $submit_date);
+ $stmt->bindParam(':created_at', $created_at);
+ $stmt->bindParam(':created_by', $created_by);
+ $stmt->execute();
$contract_apply_id = $conn->lastInsertId();
- foreach($pays as $idx=>$pay){
+ foreach ($pays as $idx => $pay) {
$kind = $idx;
$sql_str = "INSERT INTO contract_new_apply_pays (contract_apply_id, mid, pay_kind, pay_scale, pay_amount, pay_period, condition_date, created_at, created_by) VALUES (:contract_apply_id, :mid, :pay_kind, :pay_scale, :pay_amount, :pay_period, :condition_date, :created_at, :created_by)";
- $stmt = $conn -> prepare($sql_str);
- $stmt ->bindParam(':contract_apply_id', $contract_apply_id);
- $stmt ->bindParam(':mid', $mid);
- $stmt ->bindParam(':pay_kind', $kind);
- $stmt ->bindParam(':pay_scale', $pay['scale']);
- $stmt ->bindParam(':pay_amount', $pay['amount']);
- $stmt ->bindParam(':pay_period', $pay['pay_period']);
- $stmt ->bindParam(':condition_date', $pay['condition_date']);
- $stmt ->bindParam(':created_at', $created_at);
- $stmt ->bindParam(':created_by', $created_by);
- $stmt ->execute();
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':contract_apply_id', $contract_apply_id);
+ $stmt->bindParam(':mid', $mid);
+ $stmt->bindParam(':pay_kind', $kind);
+ $stmt->bindParam(':pay_scale', $pay['scale']);
+ $stmt->bindParam(':pay_amount', $pay['amount']);
+ $stmt->bindParam(':pay_period', $pay['pay_period']);
+ $stmt->bindParam(':condition_date', $pay['condition_date']);
+ $stmt->bindParam(':created_at', $created_at);
+ $stmt->bindParam(':created_by', $created_by);
+ $stmt->execute();
}
-
+ // -----處理檔案上傳 START-----
+ if (!empty($files)) {
+ $englisharr = range('a', 'z');
+ $files = $_FILES['files'];
+ $newfiles = [];
+ foreach ($files as $file) {
+ $i = 0; //新陣列的索引編號
+ foreach ($file as $key => $val) {
+ $newfiles[$i]['name'] = $files['name'][$key];
+ $newfiles[$i]['type'] = $files['type'][$key];
+ $newfiles[$i]['tmp_name'] = $files['tmp_name'][$key];
+ $newfiles[$i]['error'] = $files['error'][$key];
+ $newfiles[$i]['size'] = $files['size'][$key];
+ $i++;
+ } //foreach 第2層 end
+ }
+ $max_size = 4096 * 4096; //設定允許上傳檔案容量的最大值(1M)
+ $allow_ext = array('jpeg', 'jpg', 'png', 'JPG', 'JPEG', 'PNG', 'GIF', 'docx', 'doc', 'pdf'); //設定允許上傳檔案的類型
+ $path = '../images/contracts_new_files/';
+ if (!file_exists($path)) : mkdir($path);
+ endif;
+ $msg_result = ''; //負責接收所有檔案檢測後的回傳訊息
+ $datetime = (string)date('YmdHis');
+ $files_id = 'm' . $datetime; // 保養=>b + 日期時間
+ foreach ($newfiles as $key => $file) {
+ $randNum = rand(1000, 9999);
+ $randEnglish = $englisharr[rand(0, 25)];
+ $file_name = 'm' . (string)date('YmdHis') . $randNum . $randEnglish . $randNum . $file['name'];
+ $msg = upload_chk($file, $path, $max_size, $allow_ext, $file_name);
+ if ($msg == 1) {
+ $msg = '檔案傳送成功!';
+ $sql_str = "INSERT INTO contract_apply_files (contract_id, contract_type, file_name, file_mime, file_size, created_at, created_by) VALUES (:contract_id, :contract_type, :file_name, :file_mime, :file_size, :created_at, :created_by)";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':contract_id', $contract_apply_id);
+ $stmt->bindParam(':contract_type', $contract_type);
+ $stmt->bindParam(':file_name', $file_name);
+ $stmt->bindParam(':file_mime', $file['type']);
+ $stmt->bindParam(':file_size', $file['size']);
+ $stmt->bindParam(':created_at', $created_at);
+ $stmt->bindParam(':created_by', $created_by);
+ $stmt->execute();
+ } else {
+ throw new PDOException('檔案上傳失敗:' . $msg);
+ }
+ $msg_result .= '第' . ($key + 1) . '個上傳檔案的結果:' . $msg . ' ';
+ $src_name = $path . $file['name'];
+ if (file_exists($src_name)) {
+ //副檔名
+ $extname = pathinfo($src_name, PATHINFO_EXTENSION);
+ //主檔名
+ $basename = basename($src_name, '.' . $extname);
+ }
+ }
+ }
+ // -----處理檔案上傳 END-----
header("HTTP/1.1 201 success!");
$conn->commit();
- }else{
- $sql_str = "UPDATE contract_new_apply SET status = :status, apply_date=:apply_date, apply_type=:apply_type, case_name=:case_name, customer=:customer, manager=:manager, vat=:vat, total_price=:total_price, buy_fee=:buy_fee, install_fee=:install_fee, contact_address=:contact_address, trade_address=:trade_address, workdeadline_a=:workdeadline_a, workdeadline_b=:workdeadline_b, test_time=:test_time, freedeadline=:freedeadline, trade_address=:trade_address, trade_address=:trade_address, tradedeadline=:tradedeadline, secondPayDeadline=:secondPayDeadline, progress=:progress, person=:person, personname=:personname, submit_date=:submit_date, updated_at=:updated_at, updated_by=:updated_by WHERE mid = :mid";
- $stmt = $conn -> prepare($sql_str);
- $stmt ->bindParam(':mid', $mid);
- $stmt ->bindParam(':status', $status);
- $stmt ->bindParam(':apply_date', $apply_date);
- $stmt ->bindParam(':apply_type', $apply_type);
- $stmt ->bindParam(':case_name', $case_name);
- $stmt ->bindParam(':customer', $customer);
- $stmt ->bindParam(':manager', $manager);
- $stmt ->bindParam(':vat', $vat);
- $stmt ->bindParam(':total_price', $total_price);
- $stmt ->bindParam(':buy_fee', $buy_fee);
- $stmt ->bindParam(':install_fee', $install_fee);
- $stmt ->bindParam(':contact_address', $contact_address);
- $stmt ->bindParam(':workdeadline_a', $workdeadline_a);
- $stmt ->bindParam(':workdeadline_b', $workdeadline_b);
- $stmt ->bindParam(':test_time', $test_time);
- $stmt ->bindParam(':freedeadline', $freedeadline);
- $stmt ->bindParam(':trade_address', $trade_address);
- $stmt ->bindParam(':tradedeadline', $tradedeadline);
- $stmt ->bindParam(':secondPayDeadline', $secondPayDeadline);
- $stmt ->bindParam(':progress', $progress);
- $stmt ->bindParam(':person', $salesman);
- $stmt ->bindParam(':personname', $salesmanname);
- $stmt ->bindParam(':submit_date', $submit_date);
- $stmt ->bindParam(':updated_at', $updated_at);
- $stmt ->bindParam(':updated_by', $updated_by);
- $stmt ->execute();
+ } else {
+ $sql_str = "UPDATE contract_new_apply SET status = :status, apply_date=:apply_date, apply_type=:apply_type, case_name=:case_name, customer=:customer, manager=:manager, vat=:vat, total_price=:total_price, total_items=:total_items, buy_fee=:buy_fee, install_fee=:install_fee, contact_address=:contact_address, trade_address=:trade_address, workdeadline_a=:workdeadline_a, workdeadline_b=:workdeadline_b, test_time=:test_time, freedeadline=:freedeadline, trade_address=:trade_address, trade_address=:trade_address, tradedeadline=:tradedeadline, secondPayDeadline=:secondPayDeadline, progress=:progress, person=:person, personname=:personname, submit_date=:submit_date, updated_at=:updated_at, updated_by=:updated_by WHERE mid = :mid";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':mid', $mid);
+ $stmt->bindParam(':status', $status);
+ $stmt->bindParam(':apply_date', $apply_date);
+ $stmt->bindParam(':apply_type', $apply_type);
+ $stmt->bindParam(':case_name', $case_name);
+ $stmt->bindParam(':customer', $customer);
+ $stmt->bindParam(':manager', $manager);
+ $stmt->bindParam(':vat', $vat);
+ $stmt->bindParam(':total_price', $total_price);
+ $stmt->bindParam(':total_items', $total_items);
+ $stmt->bindParam(':buy_fee', $buy_fee);
+ $stmt->bindParam(':install_fee', $install_fee);
+ $stmt->bindParam(':contact_address', $contact_address);
+ $stmt->bindParam(':workdeadline_a', $workdeadline_a);
+ $stmt->bindParam(':workdeadline_b', $workdeadline_b);
+ $stmt->bindParam(':test_time', $test_time);
+ $stmt->bindParam(':freedeadline', $freedeadline);
+ $stmt->bindParam(':trade_address', $trade_address);
+ $stmt->bindParam(':tradedeadline', $tradedeadline);
+ $stmt->bindParam(':secondPayDeadline', $secondPayDeadline);
+ $stmt->bindParam(':progress', $progress);
+ $stmt->bindParam(':person', $salesman);
+ $stmt->bindParam(':personname', $salesmanname);
+ $stmt->bindParam(':submit_date', $submit_date);
+ $stmt->bindParam(':updated_at', $updated_at);
+ $stmt->bindParam(':updated_by', $updated_by);
+ $stmt->execute();
- foreach($pays as $idx=>$pay){
+ foreach ($pays as $idx => $pay) {
$kind = $idx;
$sql_str = "UPDATE contract_new_apply_pays SET pay_scale = :pay_scale, pay_amount = :pay_amount, pay_period = :pay_period, condition_date = :condition_date, updated_at = :updated_at, updated_by = :updated_by WHERE mid = :mid AND pay_kind = :pay_kind";
- $stmt = $conn -> prepare($sql_str);
- $stmt ->bindParam(':mid', $mid);
- $stmt ->bindParam(':pay_kind', $kind);
- $stmt ->bindParam(':pay_scale', $pay['scale']);
- $stmt ->bindParam(':pay_amount', $pay['amount']);
- $stmt ->bindParam(':pay_period', $pay['pay_period']);
- $stmt ->bindParam(':condition_date', $pay['condition_date']);
- $stmt ->bindParam(':updated_at', $updated_at);
- $stmt ->bindParam(':updated_by', $updated_by);
- $stmt ->execute();
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':mid', $mid);
+ $stmt->bindParam(':pay_kind', $kind);
+ $stmt->bindParam(':pay_scale', $pay['scale']);
+ $stmt->bindParam(':pay_amount', $pay['amount']);
+ $stmt->bindParam(':pay_period', $pay['pay_period']);
+ $stmt->bindParam(':condition_date', $pay['condition_date']);
+ $stmt->bindParam(':updated_at', $updated_at);
+ $stmt->bindParam(':updated_by', $updated_by);
+ $stmt->execute();
+ }
+ $deleted_at = date("Y-m-d H:i:s");
+ $removefiles = json_decode($_POST['removefiles'], true);
+ print_r($removefiles);
+ if(count($removefiles) > 0){
+ foreach($removefiles as $file){
+ $sql_str = "UPDATE contract_apply_files SET deleted_at = :deleted_at WHERE id = :fileid";
+ $stmt = $conn -> prepare($sql_str);
+ $stmt ->bindParam(':deleted_at', $deleted_at);
+ $stmt ->bindParam(':fileid', $file);
+ $stmt ->execute();
+ }
}
+
+
+
header("HTTP/1.1 201 success!");
$conn->commit();
}
- }catch(PDOException $e){
+ } catch (PDOException $e) {
$conn->rollback();
header("HTTP/1.1 500 failed!");
echo $e->getMessage();
- die('Error!:'.$e->getMessage());
+ die('Error!:' . $e->getMessage());
}
-
-
}
//結案同意
-if(isset($_POST['vol_no']) && !empty($_POST['vol_no']) && ($_POST['status'] == 3) ){
+if (isset($_POST['vol_no']) && !empty($_POST['vol_no']) && ($_POST['status'] == 3)) {
$status = $_POST['status'];
$vol_no = $_POST['vol_no'];
$contract_new_apply_id = $_POST['contract_new_apply_id'];
@@ -161,51 +240,52 @@ if(isset($_POST['vol_no']) && !empty($_POST['vol_no']) && ($_POST['status'] == 3
$user_id = $_POST['review_person_id'];
$review_date = date('Y-m-d H:i:s');
$conn->beginTransaction();
- try{
+ try {
$sql_str = "UPDATE contract_new_apply SET status = :status, progress = :progress, review_comment=:review_comment, review_person_id=:review_person_id, review_date=:review_date WHERE id = :contract_new_apply_id";
- $stmt = $conn -> prepare($sql_str);
- $stmt ->bindParam(':status', $status);
- $stmt ->bindParam(':progress', $progress);
- $stmt ->bindParam(':contract_new_apply_id', $contract_new_apply_id);
- $stmt ->bindParam(':review_comment', $review_comment);
- $stmt ->bindParam(':review_person_id', $user_id);
- $stmt ->bindParam(':review_date', $review_date);
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':status', $status);
+ $stmt->bindParam(':progress', $progress);
+ $stmt->bindParam(':contract_new_apply_id', $contract_new_apply_id);
+ $stmt->bindParam(':review_comment', $review_comment);
+ $stmt->bindParam(':review_person_id', $user_id);
+ $stmt->bindParam(':review_date', $review_date);
$stmt->execute();
header("HTTP/1.1 200 success!");
$conn->commit();
- }catch(PDOException $e){
+ } catch (PDOException $e) {
$conn->rollback();
header("HTTP/1.1 500 failed!");
echo $e->getMessage();
- die('Error!:'.$e->getMessage());
+ die('Error!:' . $e->getMessage());
}
}
//結案不同意(退回)
-if(isset($_POST['vol_no']) && !empty($_POST['vol_no']) && ($_POST['status'] == 2) ){
+if (isset($_POST['vol_no']) && !empty($_POST['vol_no']) && ($_POST['status'] == 2)) {
$status = $_POST['status'];
$vol_no = $_POST['vol_no'];
$contract_new_apply_id = $_POST['contract_new_apply_id'];
$progress = $_POST['progress'];
$review_comment = $_POST['review_comment'];
$user_id = $_POST['review_person_id'];
+ echo $user_id;
$review_date = date('Y-m-d H:i:s');
$conn->beginTransaction();
- try{
+ try {
$sql_str = "UPDATE contract_new_apply SET status = :status, progress = :progress, review_comment=:review_comment, review_person_id=:review_person_id, review_date=:review_date WHERE id = :contract_new_apply_id";
- $stmt = $conn -> prepare($sql_str);
- $stmt ->bindParam(':status', $status);
- $stmt ->bindParam(':progress', $progress);
- $stmt ->bindParam(':contract_new_apply_id', $contract_new_apply_id);
- $stmt ->bindParam(':review_comment', $review_comment);
- $stmt ->bindParam(':review_person_id', $user_id);
- $stmt ->bindParam(':review_date', $review_date);
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':status', $status);
+ $stmt->bindParam(':progress', $progress);
+ $stmt->bindParam(':contract_new_apply_id', $contract_new_apply_id);
+ $stmt->bindParam(':review_comment', $review_comment);
+ $stmt->bindParam(':review_person_id', $user_id);
+ $stmt->bindParam(':review_date', $review_date);
$stmt->execute();
header("HTTP/1.1 200 success!");
$conn->commit();
- }catch(PDOException $e){
+ } catch (PDOException $e) {
$conn->rollback();
header("HTTP/1.1 500 failed!");
echo $e->getMessage();
- die('Error!:'.$e->getMessage());
+ die('Error!:' . $e->getMessage());
}
-}
\ No newline at end of file
+}
diff --git a/wms/contract/contract-download.php b/wms/contract/contract-download.php
index 837bde91..dee15d1f 100644
--- a/wms/contract/contract-download.php
+++ b/wms/contract/contract-download.php
@@ -2,8 +2,8 @@
include "../header.php";
require_once('./conn.php');
//買賣1、2、3,安裝5、6 (4跟7很少有)
-if(isset($_GET['id']) && $_GET['id']!=""){
- try{
+if (isset($_GET['id']) && $_GET['id'] != "") {
+ try {
$id = $_GET['id'];
$sql_str = "SELECT pricereview_main.*, pricereview_pay.*, pricereview_item.note, pricereview_item.item_qty, account.name as accountname, account.id as accountid
FROM pricereview_main
@@ -25,7 +25,8 @@ if(isset($_GET['id']) && $_GET['id']!=""){
$stmt->execute();
$contracts = $stmt->fetchAll(PDO::FETCH_ASSOC);
$contract = $contracts[0];
- if(($contract['status'] !== "YY" && $user_id != 'M0107') && $user_id != 'M0174'){
+ $contract_apply_id = $contract['id'];
+ if (($contract['status'] !== "YY" && $user_id != 'M0107') && $user_id != 'M0174' && $user_id != 'M0225') {
echo '";
- exit;
- }
+ // if (count($customer) <= 0) {
+ // echo "";
+ // exit;
+ // }
$buyArr = [];
$buyNo2Pay = false;
$buy_total_price = 0;
$installArr = [];
$install_total_price = 0;
// $noteArr = explode(",", $contracts[0]['note']);
- $noteArr = array(1,1,1,1,1);
- $qty = $contracts[0]['item_qty'];
- // print_r($contracts);
- // print_r($buyArr);
- foreach($contracts as $idx=>$amount){
+ $noteArr = array(1, 1, 1, 1, 1);
+ $qty = $contracts[0]['total_items'];
+ foreach ($contracts as $idx => $amount) {
$isset = false;
- if($amount['pay_kind']==5 || $amount['pay_kind']==6){
- echo "111111";
- if($amount['pay_scale'] >= 0){
+ if ($amount['pay_kind'] == 5 || $amount['pay_kind'] == 6) {
+ if ($amount['pay_scale'] >= 0) {
$install_total_price = $install_total_price + $amount['pay_amount'];
- $installArr[] = ['installment'=> $amount['pay_kind'], 'scale'=> $amount['pay_scale'], 'amount'=> $amount['pay_amount'], 'note'=>$amount['note']];
+ $installArr[] = ['installment' => $amount['pay_kind'], 'scale' => $amount['pay_scale'], 'amount' => $amount['pay_amount'], 'pay_period' => $amount['pay_period']];
}
}
- if($amount['pay_kind']==1 || $amount['pay_kind']==2 || $amount['pay_kind']==3){
- if($amount['pay_scale'] > 0){
+ if ($amount['pay_kind'] == 1 || $amount['pay_kind'] == 2 || $amount['pay_kind'] == 3) {
+ if ($amount['pay_scale'] > 0) {
$buy_total_price = $buy_total_price + $amount['pay_amount'];
- foreach($buyArr as $buy){
- if($buy['installment'] == $amount['pay_kind']){
+ foreach ($buyArr as $buy) {
+ if ($buy['installment'] == $amount['pay_kind']) {
$isset = true;
}
}
- if(!$isset){{
- $buyArr[] = ['installment'=>$amount['pay_kind'], 'scale'=>$amount['pay_scale'], 'amount'=>$amount['pay_amount'], 'note'=>$amount['note']];
- }
- if($amount['pay_kind'] == 2){
- $buyNo2Pay = true;
+ if (!$isset) { {
+ $buyArr[] = ['installment' => $amount['pay_kind'], 'scale' => $amount['pay_scale'], 'amount' => $amount['pay_amount'], 'pay_period' => $amount['pay_period']];
+ }
+ if ($amount['pay_kind'] == 2) {
+ $buyNo2Pay = true;
+ }
}
}
- }
-
}
}
- // print_r($buyArr);
-
- }
- catch (PDOException $e ){
- die("ERROR!!!: ". $e->getMessage());
+ $sql_str = "SELECT file_name FROM contract_apply_files WHERE contract_id = :contract_id AND deleted_at IS NULL";
+ $sql_str = "SELECT contract_apply_files.*, contract_new_apply.id as apply_id FROM contract_apply_files LEFT JOIN contract_new_apply ON contract_apply_files.contract_id = contract_new_apply.id WHERE contract_new_apply.mid = :mid AND contract_apply_files.deleted_at IS NULL";
+ $stmt = $conn->prepare($sql_str);
+ $stmt->bindParam(':mid', $id);
+ $stmt->execute();
+ $files = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $files_count = count($files);
+ } catch (PDOException $e) {
+ die("ERROR!!!: " . $e->getMessage());
}
- echo $buy_total_price;
}
?>
@@ -98,25 +98,25 @@ if(isset($_GET['id']) && $_GET['id']!=""){
-
-
-
-
-
-
-
+
+
+ -->
+
+ 生成買賣合約書
-
+
+
-
- 重新輸入
- 預覽
-
-
-
- 電梯買賣合約書
-
-
-
- 合約書編號:
-
-
-
- (即買方,以下簡稱為甲方)
-
-
- 立合約書人
-
-
- (即賣方,以下簡稱為乙方)
-
-
+
+
+ 預覽
+
+
+
+
+ 電梯買賣合約書
+
+
+
+
+ 合約書編號:
+
+
+
+
+
+ (即買方,以下簡稱為甲方)
+
+
+
+ 立合約書人
+
+
+
+
+ (即賣方,以下簡稱為乙方)
+
+
+
@@ -172,8 +184,8 @@ if(isset($_GET['id']) && $_GET['id']!=""){
-
-
+
+
@@ -181,59 +193,72 @@ if(isset($_GET['id']) && $_GET['id']!=""){
-
+
+
-
-
-
-
-
-
- 電梯買賣合約書
-
-
-
- 合約書編號:
-
-
-
- (即買方,以下簡稱為甲方)
-
-
- 立合約書人
-
-
- (即賣方,以下簡稱為乙方)
-
-
+
+
+
+
+
+
+
+ 電梯買賣合約書
+
+
+
+
+ 合約書編號:
+
+
+
-
+
+ (即買方,以下簡稱為甲方)
-
-
-
-
-
+
+ 立合約書人
+
+
+
+
+ (即賣方,以下簡稱為乙方)
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
-