text:
var iaplightProduct1 = {
    "productId": "com.mycompany.myproduct.weekly.v1",
    "title": "Premium weekly subscription",
    "description": "Premium weekly subscription to my beatiful product",
    "price": "€0,99"
};
var iaplightProduct2 = {
    "productId": "com.mycompany.myproduct.montly.v1",
    "title": "Premium montly subscription",
    "description": "Premium montly subscription to my beatiful product",
    "price": "€3,99"
};
var iaplightReceiptBundleOrg = {
    "originalAppVersion": "1.0",
    "appVersion": "0.1.0",
    "inAppPurchases": [ {
        "transactionIdentifier":"123412341234",
        "quantity":1,
        "purchaseDate":"2016-07-05T10:15:21Z",
        "productId":iaplightProduct1.productId,
        "originalPurchaseDate":"2016-07-05T10:15:22Z",
        "subscriptionExpirationDate":"2016-07-05T10:18:21Z",
        "originalTransactionIdentifier":"123412341234",
        "webOrderLineItemID":-1497665198,
        "cancellationDate":null
    },
    {
        "transactionIdentifier":"123412341256",
        "quantity":1,
        "purchaseDate":"2016-07-03T10:15:21Z",
        "productId":iaplightProduct1.productId,
        "originalPurchaseDate":"2016-07-03T10:15:22Z",
        "subscriptionExpirationDate":"2016-07-03T10:18:21Z",
        "originalTransactionIdentifier":"123412341256",
        "webOrderLineItemID":-1497665195,
        "cancellationDate":null
    } ],
    "bundleIdentifier": "com.mycompany.myapp"
};
var iaplightReceiptBundle = JSON.parse(JSON.stringify(iaplightReceiptBundleOrg));

var iaplightRestoreResult = {};
var iaplightRestoreResultIosBase = [
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-05T10:27:21Z","transactionId":"1000000222595453","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-05T10:21:21Z","transactionId":"1000000222595454","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T11:04:50Z","transactionId":"1000000222595455","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T10:58:50Z","transactionId":"1000000222595456","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T11:01:50Z","transactionId":"1000000222595457","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T12:59:06Z","transactionId":"1000000222595458","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-05T10:30:21Z","transactionId":"1000000222595459","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T12:49:07Z","transactionId":"1000000222595460","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T11:07:50Z","transactionId":"1000000222595461","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-05T10:15:21Z","transactionId":"1000000222595462","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-05T10:18:21Z","transactionId":"1000000222595463","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T10:55:50Z","transactionId":"1000000222595464","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-05T10:24:21Z","transactionId":"1000000222595465","state":3},
    {"productId":"com.mycompany.myproduct.weekly.v1","date":"2016-07-08T11:10:50Z","transactionId":"1000000222595466","state":3}
];
var iaplightRestoreResultAndroidOk = [
    {
        "productId":iaplightProduct1.productId,
        "transactionId":"",
        "type":"subs",
        "productType":"subs",
        "signature":"xxxxxxxx==",
        "receipt":"{\"packageName\":\"com.mycompany.myproduct\",\"productId\":\""+iaplightProduct1.productId+"\",\"purchaseTime\":1491209382421,\"purchaseState\":0,\"purchaseToken\":\"nknmjmadpdhibpnaeibbxxxx\",\"autoRenewing\":true}"
    }
];

var iaplightRestoreResultAndroidKo = [];

var iaplightSubscribeMockResult = {
"transactionId":"1000000221696692",
"receipt":"MXXXX"
};
var iaplightSubscribeMockResultIos = {
"transactionId":"1000000221696692",
"receipt":"MXXXX"
};
var timePurchase10MinAgo = ((
    (new Date(
            (   +(new Date()) - 600 * 1000  )
        )
    ).getTime()) / 1000).toFixed(0);
var timePurchase10MinAgoStr = (new Date(timePurchase10MinAgo*1000)).toISOString()

var iaplightSubscribeMockResultAndroid = {
    "signature":"EjwaorJ8D5yD9F7t7yQgRvHBjk+Ga53seIilDuzzLmv05cc0LiV/WAqUE+NHq+CGTnogtxnb/rjSAxo+K2S6xg8kskZQvRzYNxo0YBhvhCRr5VKrvQO+VZTwM3RKfNlDGdCYw7rEuuvcvH733wzPGdeKmLKw4JI7wk6ViVMEgq7ub7dOTwiv8rSVqf/2sIbD96yhh3d55jWiBdbwCzLvaVcLKTAD6oG78bW7n9FbTAcdDEMxAeNEDJw90fANA/MXvvO1tp6rcFy/emqDCZcinv+zal5rQQc7M372YW6iBqWWm+zemexH6DrVsdjdGEsI6X1Rmk8Y8M1bnwnYKCACaA==",
    "productId":iaplightProduct1.productId,
    "transactionId":"gjmkkfbapgplpdallcgpbaol.AO-J1OxwQeGM0H3ru88F1BVqSYtUT-4VsS3U9a0tlWomLk7kvvpNQoMlAVX3_mZ2aiu5X50luuLSeO31QxwwldN9jczTU_H6UMkD1tq1hLILWE1-nAkq9VrOpoW0Jz4rbQnUwZHb_wwZ",
    "type":"subs",
    "productType":"subs",
    "receipt":"{\"packageName\":\"com.mycompany.myproduct\", \"productId\":\""+iaplightProduct1.productId+"\", \"purchaseTime\":"+timePurchase10MinAgo+", \"purchaseState\":0, \"purchaseToken\":\"4rbQnUwZHb_wwZ\", \"autoRenewing\":true }"
};
var iaplightSubscribeResultAndroid = {
    "productId": iaplightProduct1.productId,
    "transactionId": iaplightSubscribeMockResultAndroid.transactionId,
    "purchaseDate": timePurchase10MinAgoStr,
    "purchaseTime": timePurchase10MinAgo,
};
var iaplightSubscribeResultIos = {
    "productId": iaplightProduct1.productId,
    "transactionId": iaplightReceiptBundle.inAppPurchases[0].transactionIdentifier,
    "purchaseDate": timePurchase10MinAgoStr,
    "purchaseTime": timePurchase10MinAgo,
};

describe("Stargate IAP Light", function() {

    beforeEach(function() {
		hybrid_conf = null;
		country = null;
        isStargateOpen = false;
		isStargateInitialized = false;

		specTestMock = {
			onDeviceReady: function() {
				return onDeviceReady();
			}
		};

		cookie_mock._val.hybrid = 1;
		window.Cookies = cookie_mock;

		window.device = spec_device_mock;
		window.hostedwebapp = hostedwebapp_mock;
		window.cordova = cordova_mock;
		window.StatusBar = statusbar_mock;
		navigator.splashscreen = navigator_splashscreen_mock;
        navigator.connection = navigator_connection_mock;
		window.store = store_mock;
		window.storekit = storekit_mock;

		//log = jasmine.createSpy();

		getManifest = function(){
			return Promise.resolve(manifest_mock);
		};

        document.removeEventListener("deviceready",onDeviceReady, false);

        if (!window.plugins) {
            window.plugins = {};
        }
        // reset receipt bundle
        iaplightReceiptBundle = JSON.parse(JSON.stringify(iaplightReceiptBundleOrg))

        window.inAppPurchase = {
            getProducts: function(productsId) {
                return new Promise(function(resolve,reject){
                    var res = [];
                    productsId.forEach(function(pidParam){
                        if (pidParam === iaplightProduct1.productId) {
                            res.push(iaplightProduct1);
                        } else if (pidParam === iaplightProduct2.productId) {
                            res.push(iaplightProduct2);
                        }
                    });
                    resolve(res);
                });
            },
            restorePurchases: function(productId) {
                return new Promise(function(resolve,reject){
                    resolve(iaplightRestoreResult);
                });
            },
            subscribe: function(productId) {
                return new Promise(function(resolve,reject){
                    resolve(iaplightSubscribeMockResult);
                });
            },
            getReceiptBundle: function() {
                return new Promise(function(resolve,reject){
                    resolve(iaplightReceiptBundle);
                });
            }
        };

        iaplight.__clean__();
    });

	it("isInitialized is false", function() {
		expect(stargatePublic.isInitialized()).toBeFalsy();
	});

	it("isOpen is false", function() {
		expect(stargatePublic.isOpen()).toBeFalsy();
	});

	it("getProductInfo require initialization", function(done) {
        var res = stargatePublic.iaplight.getProductInfo("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/not initialized/);
		    done();
		});
	});

	it("subscribe require initialization", function(done) {
        var res = stargatePublic.iaplight.subscribe("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/not initialized/);
		    done();
		});
    });

    it("subscribeReceipt require initialization", function(done) {
        var res = stargatePublic.iaplight.subscribeReceipt("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/not initialized/);
		    done();
		});
	});

	it("isSubscribed require initialization", function(done) {
        var res = stargatePublic.iaplight.isSubscribed(iaplightReceiptBundle.inAppPurchases[0].productId);
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/not initialized/);
		    done();
		});
	});

    it("restore require initialization", function(done) {
        var res = stargatePublic.iaplight.restore("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/not initialized/);
		    done();
		});
	});

    it("getProductInfo require opened stargate", function(done) {
        isStargateInitialized = true;
        var res = stargatePublic.iaplight.getProductInfo("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Stargate closed/);
		    done();
		});
	});

	it("subscribe require opened stargate", function(done) {
        isStargateInitialized = true;
        var res = stargatePublic.iaplight.subscribe("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Stargate closed/);
		    done();
		});
    });

    it("subscribeReceipt require opened stargate", function(done) {
        isStargateInitialized = true;
        var res = stargatePublic.iaplight.subscribeReceipt("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Stargate closed/);
		    done();
		});
	});

	it("getExpireDate require opened stargate", function(done) {
        isStargateInitialized = true;
        var res = stargatePublic.iaplight.isSubscribed(iaplightReceiptBundle.inAppPurchases[0].productId);
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Stargate closed/);
		    done();
		});
	});

    it("restore require opened stargate", function(done) {
        isStargateInitialized = true;
        var res = stargatePublic.iaplight.restore();
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Stargate closed/);
		    done();
		});
	});

    it("getProductInfo require module init", function(done) {
        isStargateInitialized = true;
        isStargateOpen = true;
        var res = stargatePublic.iaplight.getProductInfo("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Not initialized/);
		    done();
		});
	});

	it("subscribe require module init", function(done) {
        isStargateInitialized = true;
        isStargateOpen = true;
        var res = stargatePublic.iaplight.subscribe("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Not initialized/);
		    done();
		});
    });

    it("subscribeReceipt require module init", function(done) {
        isStargateInitialized = true;
        isStargateOpen = true;
        var res = stargatePublic.iaplight.subscribeReceipt("com.myproduct");
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Not initialized/);
		    done();
		});
	});

	it("getExpireDate require module init", function(done) {
        isStargateInitialized = true;
        isStargateOpen = true;
        var res = stargatePublic.iaplight.isSubscribed(iaplightReceiptBundle.inAppPurchases[0].productId);
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Not initialized/);
		    done();
		});
	});

    it("restore require module init", function(done) {
        isStargateInitialized = true;
        isStargateOpen = true;
        var res = stargatePublic.iaplight.restore();
        expect(res.then).toBeDefined();
		res.catch(function(message) {
            expect(message).toMatch(/Not initialized/);
		    done();
		});
	});

    it("initialize require cordova plugin", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        window.inAppPurchase = null;

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        expect(init.then).toBeDefined();
        init.catch(function(message) {
			//console.log("iaplight.init catch: "+message);
            expect(message).toMatch(/missing cordova plugin/);
		    done();
		});
	});

    it("initialize check parameters", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        var init = iaplight.initialize({
            //productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        expect(init.then).toBeDefined();
        init.catch(function(message) {
			//console.log("iaplight.init catch: "+message);
            expect(message).toMatch(/missing parameter productsId/);
		    done();
		});
	});
    it("initialize check parameters is array", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        var init = iaplight.initialize({
            productsIdAndroid: "aaaaa",
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        expect(init.then).toBeDefined();
        init.catch(function(message) {
			//console.log("iaplight.init catch: "+message);
            expect(message).toMatch(/must be an array/);
		    done();
		});
	});
    it("initialize check parameters is array lenght", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        var init = iaplight.initialize({
            productsIdAndroid: []
        });
        expect(init.then).toBeDefined();
        init.catch(function(message) {
			//console.log("iaplight.init catch: "+message);
            expect(message).toMatch(/must contains at least a productid/);
		    done();
		});
	});

    it("initialize return same promise as before", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        expect(init.then).toBeDefined();
        init.catch(function(message) {
			//console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});
        init.then(function(result) {
            var init2 = iaplight.initialize({
                productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
                productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
            });
            expect(init2).toBe(init);
            done();
		});
	});

    it("initialize ios", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "iOS";

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId],
            productsIdIos: [iaplightProduct2.productId],
        });
        expect(init.then).toBeDefined();
        init.catch(function(message) {
			//console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});
        init.then(function(result) {
			//console.log("iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate: "+iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            //console.log("result: "+result);
            expect(result).toEqual([iaplightProduct2]);
            done();
		});
	});

    it("iaplight isSubscribed Android Subscribed", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";
        appPackageName = "com.mycompany.myproduct";
        iaplightRestoreResult = iaplightRestoreResultAndroidOk;

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.isSubscribed(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate: "+iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            //console.log("result: "+result);
            var isSubscribed = true;

            expect(result).toEqual(isSubscribed)
            done();
		});
	});

    it("iaplight isSubscribed Android Expired", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        iaplightRestoreResult = iaplightRestoreResultAndroidKo;

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.isSubscribed(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate: "+iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            //console.log("result: "+result);
            var isSubscribed = false;

            expect(result).toEqual(isSubscribed)
            done();
		});
	});

    it("iaplight isSubscribed iOS subscribed", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "iOS";

        // set a purchaseDate 10 minutes in the past
        iaplightReceiptBundle.inAppPurchases[0].purchaseDate =
            iaplightReceiptBundle.inAppPurchases[0].originalPurchaseDate =
            (new Date((+(new Date()) - 600 * 1000))).toISOString();

        // set a subscriptionExpirationDate 10 minutes in the future
        iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate =
            (new Date((+(new Date()) + 600 * 1000))).toISOString();

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.isSubscribed(iaplightReceiptBundle.inAppPurchases[0].productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate: "+iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            //console.log("result: "+result);
            var dateMock = new Date(iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            var isSubscribed = true;

            expect(result).toEqual(isSubscribed)
            done();
		});
	});

    it("iaplight isSubscribed iOS expired", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "iOS";

        // set a purchaseDate 20 minutes in the past
        iaplightReceiptBundle.inAppPurchases[0].purchaseDate =
            iaplightReceiptBundle.inAppPurchases[0].originalPurchaseDate =
            (new Date((+(new Date()) - 1200 * 1000))).toISOString();

        // set a subscriptionExpirationDate 10 minutes in the past
        iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate =
            (new Date((+(new Date()) - 600 * 1000))).toISOString();

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.isSubscribed(iaplightReceiptBundle.inAppPurchases[0].productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate: "+iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            //console.log("result: "+result);
            var dateMock = new Date(iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate);
            var isSubscribed = false;

            expect(result).toEqual(isSubscribed)
            done();
		});
	});

    it("iaplight getProductInfo", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.getProductInfo(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightProduct1)
		});

        var res2 = stargatePublic.iaplight.getProductInfo(iaplightProduct2.productId);

        expect(res2.then).toBeDefined();

		res2.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res2.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightProduct2)
		    done();
		});
	});

    it("iaplight subscribe Android", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        appPackageName = "com.mycompany.myproduct";
        iaplightSubscribeMockResult = iaplightSubscribeMockResultAndroid;

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.subscribe(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightSubscribeResultAndroid);
            done();
		});
	});

    it("iaplight subscribe iOS", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "iOS";

        appPackageName = "com.mycompany.myproduct";
        iaplightSubscribeMockResult = iaplightSubscribeMockResultIos;

        // set a purchaseDate 10 minutes in the past
        iaplightReceiptBundle.inAppPurchases[0].purchaseDate =
            iaplightReceiptBundle.inAppPurchases[0].originalPurchaseDate =
            timePurchase10MinAgoStr;

        // set a subscriptionExpirationDate 10 minutes in the future
        iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate =
            (new Date((+(new Date(timePurchase10MinAgo*1000)) + 1200 * 1000))).toISOString();

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.subscribe(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightSubscribeResultIos);
            done();
		});
	});

    it("iaplight subscribeReceipt Android", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";

        appPackageName = "com.mycompany.myproduct";
        iaplightSubscribeMockResult = iaplightSubscribeMockResultAndroid;

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.subscribeReceipt(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightSubscribeMockResultAndroid);
            done();
		});
	});

    it("iaplight subscribeReceipt iOS", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "iOS";

        appPackageName = "com.mycompany.myproduct";
        iaplightSubscribeMockResult = iaplightSubscribeMockResultIos;

        // set a purchaseDate 10 minutes in the past
        iaplightReceiptBundle.inAppPurchases[0].purchaseDate =
            iaplightReceiptBundle.inAppPurchases[0].originalPurchaseDate =
            timePurchase10MinAgoStr;

        // set a subscriptionExpirationDate 10 minutes in the future
        iaplightReceiptBundle.inAppPurchases[0].subscriptionExpirationDate =
            (new Date((+(new Date(timePurchase10MinAgo*1000)) + 1200 * 1000))).toISOString();

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.subscribeReceipt(iaplightProduct1.productId);

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightSubscribeMockResultIos);
            done();
		});
	});

    it("iaplight restore empty with false", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";
        iaplightRestoreResult = false;

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.restore();

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightRestoreResult);
            done();
		});
	});

    it("iaplight getActiveSubscriptionsInfo Android", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "Android";
        iaplightRestoreResult = {};

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.getActiveSubscriptionsInfo();

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightRestoreResult);
            done();
		});
	});

    it("iaplight getActiveSubscriptionsInfo iOS", function(done) {

        isStargateInitialized = true;
        isStargateOpen = true;
        runningDevice.platform = "iOS";
        iaplightRestoreResult = {};

        var init = iaplight.initialize({
            productsIdAndroid: [iaplightProduct1.productId, iaplightProduct2.productId],
            productsIdIos: [iaplightProduct1.productId, iaplightProduct2.productId],
        });
        init.catch(function(message) {
			console.log("iaplight.init catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

        expect(init.then).toBeDefined();

		var res = stargatePublic.iaplight.getActiveSubscriptionsInfo();

        expect(res.then).toBeDefined();

		res.catch(function(message) {
			console.log("stargatePublic.iaplight.getProductInfo catch: "+message);
            expect(message).not.toBeDefined();
		    done();
		});

		res.then(function(result) {
			//console.log("stargatePublic.socialShare catch: "+result);
            expect(result).toEqual(iaplightRestoreResult);
            done();
		});
	});

});


text:
#ifndef CRIMILD_FOUNDATION_POLICIES_THREADING_
#define CRIMILD_FOUNDATION_POLICIES_THREADING_

#include <thread>
#include <mutex>

namespace crimild {

	namespace policies {

		class SingleThreaded {
		public:
			class Lock {
			public:
				explicit Lock( const SingleThreaded * ) { }
				~Lock( void ) { }
			};
		};

		class ObjectLevelLockable {
		public:
			using Mutex = std::mutex;

		public:
			class Lock {
			public:
				Lock( const ObjectLevelLockable *host )
				{
					_host = host;
					_host->_mutex.lock();
				}

				Lock( const Lock & ) = delete;

				~Lock( void )
				{
					_host->_mutex.unlock();
					_host = nullptr;
				}

			private:
				const ObjectLevelLockable *_host = nullptr;
			};

		private:
			mutable Mutex _mutex;
		};

		class ClassLevelLockable {
			using Mutex = std::mutex;

		public:
			class Lock {
			public:
				explicit Lock( const ClassLevelLockable * )
				{
					_mutex.lock();
				}

				Lock( const Lock & ) = delete;

				~Lock( void )
				{
					_mutex.unlock();
				}
			};

		private:
			static Mutex _mutex;
		};

	}

}

#endif

redpajama_set_name: RedPajamaGithub


text:
#include "SignalFinderTools.h"
using namespace std;

map<int, vector<JPetSigCh>> SignalFinderTools::getSigChsPMMapById(const JPetTimeWindow* timeWindow)
{
	map<int, vector<JPetSigCh>> sigChsPMMap;
	if(!timeWindow) {
		WARNING("timeWindow pointer is not set");
		return sigChsPMMap;
	}

	//map Signal Channels in this Time window according to PM they belong to
	const unsigned int nSigChs = timeWindow->getNumberOfSigCh();
	for(unsigned int i = 0; i < nSigChs; i++) {
		JPetSigCh sigCh = timeWindow->operator[](i);
		int pmt_id = sigCh.getPM().getID();
		auto search = sigChsPMMap.find(pmt_id);
		if (search == sigChsPMMap.end()) {
			vector<JPetSigCh> tmp;
			tmp.push_back(sigCh);
			sigChsPMMap.insert(pair<int, vector<JPetSigCh>>(pmt_id, tmp));
		} else {
			search->second.push_back(sigCh);
		}
	}

	return sigChsPMMap;
}

//method with loop of building raw signals for whole PM map
vector<JPetRawSignal> SignalFinderTools::buildAllSignals(Int_t timeWindowIndex,
					map<int, vector<JPetSigCh>> sigChsPMMap,
					int numOfThresholds,
					JPetStatistics& stats,
					bool saveControlHistos,
					double sigChEdgeMaxTime,
					double sigChLeadTrailMaxTime)
{

	vector<JPetRawSignal> allSignals;

	for (auto & sigChPair : sigChsPMMap) {
		vector<JPetRawSignal> currentSignals = buildRawSignals(timeWindowIndex, sigChPair.second, numOfThresholds, stats, saveControlHistos, sigChEdgeMaxTime, sigChLeadTrailMaxTime);
		allSignals.insert(allSignals.end(), currentSignals.begin(), currentSignals.end());
	}

	return allSignals;
}

//sorting method
bool sortByTimeValue(JPetSigCh sig1, JPetSigCh sig2)
{
	return (sig1.getValue() < sig2.getValue());
}

//method creating Raw signals form vector of Signal Channels
vector<JPetRawSignal> SignalFinderTools::buildRawSignals(Int_t timeWindowIndex,
					const vector<JPetSigCh>& sigChFromSamePM,
					int numOfThresholds,
					JPetStatistics& stats,
					bool saveControlHistos,
					double sigChEdgeMaxTime,
					double sigChLeadTrailMaxTime)
{
	vector<JPetRawSignal> rawSigVec;

	//Threshold number check - fixed number equal 4
	if (numOfThresholds != 4) {
		ERROR("This function is ment to work with 4 thresholds only!");
		return rawSigVec;
	}

	vector<JPetSigCh> tmp;
	vector<vector<JPetSigCh>> thresholdSigCh(2 * numOfThresholds, tmp);

	bool errorOccured = false;

	//division into subvectors according to threshold number:
	//0-3 leading, 4-7 trailing
	for (const JPetSigCh & sigCh : sigChFromSamePM) {
		auto threshNum = sigCh.getThresholdNumber();
		if ((threshNum <= 0) || (threshNum > 2 * numOfThresholds)) {
			ERROR("Threshold number out of range:" + std::to_string(threshNum));
			errorOccured = true;
			break;
		}

		if (sigCh.getType() == JPetSigCh::Leading) {
			thresholdSigCh.at(sigCh.getThresholdNumber() - 1).push_back(sigCh);
		} else if (sigCh.getType() == JPetSigCh::Trailing) {
			thresholdSigCh.at(sigCh.getThresholdNumber() + numOfThresholds - 1)
							.push_back(sigCh);
		}
	}

	if (errorOccured) {
		return rawSigVec;
	}

	//probably not needed vector sorting according to Signal channel time values
	for (auto thrVec : thresholdSigCh) {
		sort(thrVec.begin(), thrVec.end(), sortByTimeValue);
	}

	assert(thresholdSigCh.size() > 0);
	while (thresholdSigCh.at(0).size() > 0) {

		JPetRawSignal rawSig;
		rawSig.setTimeWindowIndex(timeWindowIndex);
		rawSig.setPM(thresholdSigCh.at(0).at(0).getPM());
		rawSig.setBarrelSlot(thresholdSigCh.at(0).at(0).getPM().getBarrelSlot());

		//first leading added by default
		rawSig.addPoint(thresholdSigCh.at(0).at(0));

		//looking for points from other thresholds that belong to the same leading edge
		//and search for equivalent trailing edge points
		//first thr trailing

		assert(thresholdSigCh.at(0).size() > 0);
		assert(thresholdSigCh.size() > 4);

		int closestTrailingSigCh0 = findTrailingSigCh(
						thresholdSigCh.at(0).at(0),
						thresholdSigCh.at(4),
						sigChLeadTrailMaxTime);

		if (closestTrailingSigCh0 != -1) {
			rawSig.addPoint(thresholdSigCh.at(4).at(closestTrailingSigCh0));
			thresholdSigCh.at(4).erase(thresholdSigCh.at(4).begin()
							+ closestTrailingSigCh0);
		}

		//second thr leading and trailing
		int nextThrSigChIndex1 = findSigChOnNextThr(
						thresholdSigCh.at(0).at(0).getValue(),
						thresholdSigCh.at(1),
						sigChEdgeMaxTime);

		if (nextThrSigChIndex1 != -1) {

			int closestTrailingSigCh1 = findTrailingSigCh(
							thresholdSigCh.at(0).at(0),
							thresholdSigCh.at(5),
							sigChLeadTrailMaxTime);

			if (closestTrailingSigCh1 != -1) {
				rawSig.addPoint(thresholdSigCh.at(5).at(closestTrailingSigCh1));
				thresholdSigCh.at(5).erase(thresholdSigCh.at(5).begin()
								+ closestTrailingSigCh1);
      			}

			rawSig.addPoint(thresholdSigCh.at(1).at(nextThrSigChIndex1));
			thresholdSigCh.at(1).erase(thresholdSigCh.at(1).begin()
								+ nextThrSigChIndex1);
		}

		//third thr leading and trailing
		int nextThrSigChIndex2 = findSigChOnNextThr(
						thresholdSigCh.at(0).at(0).getValue(),
						thresholdSigCh.at(2),
						sigChEdgeMaxTime);

		if (nextThrSigChIndex2 != -1) {

			int closestTrailingSigCh2 = findTrailingSigCh(
							thresholdSigCh.at(0).at(0),
							thresholdSigCh.at(6),
							sigChLeadTrailMaxTime);

			if (closestTrailingSigCh2 != -1) {
				rawSig.addPoint(thresholdSigCh.at(6).at(closestTrailingSigCh2));
				thresholdSigCh.at(6).erase(thresholdSigCh.at(6).begin()
								+ closestTrailingSigCh2);
			}

			rawSig.addPoint(thresholdSigCh.at(2).at(nextThrSigChIndex2));
			thresholdSigCh.at(2).erase(thresholdSigCh.at(2).begin()
								+ nextThrSigChIndex2);
		}

		//fourth thr leading and trailing
		int nextThrSigChIndex3 = findSigChOnNextThr(
				thresholdSigCh.at(0).at(0).getValue(),
				thresholdSigCh.at(3),
				sigChEdgeMaxTime);

		if (nextThrSigChIndex3 != -1) {

			int closestTrailingSigCh3 = findTrailingSigCh(
							thresholdSigCh.at(0).at(0),
							thresholdSigCh.at(7),
							sigChLeadTrailMaxTime);

			if (closestTrailingSigCh3 != -1) {
				rawSig.addPoint(thresholdSigCh.at(7).at(closestTrailingSigCh3));
				thresholdSigCh.at(7).erase(thresholdSigCh.at(7).begin()
								+ closestTrailingSigCh3);
			}

			rawSig.addPoint(thresholdSigCh.at(3).at(nextThrSigChIndex3));
			thresholdSigCh.at(3).erase(thresholdSigCh.at(3).begin()
								+ nextThrSigChIndex3);
		}

		//adding created Raw Signal to vector
		rawSigVec.push_back(rawSig);
		thresholdSigCh.at(0).erase(thresholdSigCh.at(0).begin() + 0);
	}

	//filling controll histograms
	if (saveControlHistos) {
		stats.getHisto1D("remainig_leading_sig_ch_per_thr")
					.Fill(1, thresholdSigCh.at(0).size());
		stats.getHisto1D("remainig_leading_sig_ch_per_thr")
					.Fill(2, thresholdSigCh.at(1).size());
		stats.getHisto1D("remainig_leading_sig_ch_per_thr")
					.Fill(3, thresholdSigCh.at(2).size());
		stats.getHisto1D("remainig_leading_sig_ch_per_thr")
					.Fill(4, thresholdSigCh.at(3).size());
		stats.getHisto1D("remainig_trailing_sig_ch_per_thr")
					.Fill(1, thresholdSigCh.at(4).size());
		stats.getHisto1D("remainig_trailing_sig_ch_per_thr")
					.Fill(2, thresholdSigCh.at(5).size());
		stats.getHisto1D("remainig_trailing_sig_ch_per_thr")
					.Fill(3, thresholdSigCh.at(6).size());
		stats.getHisto1D("remainig_trailing_sig_ch_per_thr")
					.Fill(4, thresholdSigCh.at(7).size());
	}

	return rawSigVec;
}

//method of finding Signal Channels that belong to the same leading edge
//not more than sigChEdgeMaxTime away. Defined in ps.
int SignalFinderTools::findSigChOnNextThr(Double_t sigChValue, const vector<JPetSigCh>& sigChVec, double sigChEdgeMaxTime)
{
	for (Int_t i = 0; i < sigChVec.size(); i++) {
		if (fabs(sigChValue - sigChVec.at(i).getValue()) < sigChEdgeMaxTime) {
			return i;
		}
	}
	return -1;
}

//method of finding trailing edge SigCh that suits certian leading edge SigCh
//not further away than sigChLeadTrailMaxTime in ps
//if more than one trailing edge SigCh found, returning one with the smallest index
//that is equivalent of SigCh earliest in time
int SignalFinderTools::findTrailingSigCh(const JPetSigCh& leadingSigCh, const vector<JPetSigCh>& trailingSigChVec, double sigChLeadTrailMaxTime)
{
	vector<int> trailingFoundIdices;
	for (Int_t i = 0; i < trailingSigChVec.size(); i++) {
		if (fabs(leadingSigCh.getValue() - trailingSigChVec.at(i).getValue()) < sigChLeadTrailMaxTime)
		trailingFoundIdices.push_back(i);
	}
	if (trailingFoundIdices.size() == 0) return -1;
	sort(trailingFoundIdices.begin(), trailingFoundIdices.end());
	return trailingFoundIdices.at(0);
}


text:
package mawa.com.pl.springmvc.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import mawa.com.pl.springmvc.bean.Contact;
import mawa.com.pl.springmvc.bean.ExclusiveContact;
import mawa.com.pl.springmvc.bean.Order;
import mawa.com.pl.springmvc.bean.Player;
import mawa.com.pl.springmvc.bean.Team;
import mawa.com.pl.springmvc.dao.ContactRepo;
import mawa.com.pl.springmvc.dao.TeamRepo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ContactsController {

	@Autowired
	ContactRepo repository;

	@Autowired
	TeamRepo teamRepository;

	@Autowired
	Validator validator;

	@RequestMapping("/uuid")
	@ResponseBody
	public Contact getUUID(HttpServletResponse response) throws IOException {
		Contact cnt = new Contact();
		cnt.setName(UUID.randomUUID().toString());
			Set<ConstraintViolation<Contact>> exc = validator.validate(cnt);
			if(!exc.isEmpty()){
				response.sendError(HttpStatus.BAD_REQUEST.value(), exc.toString());
			}else{
				repository.save(cnt);
			}
		return cnt;
	}

	/**
	 * One-To-Many with JOIN table
	 */
	@RequestMapping("/uuid2")
	@ResponseBody
	public ExclusiveContact getUUID2() {
		ExclusiveContact cnt = new ExclusiveContact();
		cnt.setName(UUID.randomUUID().toString());
		cnt.setGoldenCardNo(UUID.randomUUID().toString());
		Order order = new Order();
		order.setOrderUUID(UUID.randomUUID().toString());
		cnt.addOrder(order);
		repository.save(cnt);
		return cnt;
	}

	/**
	 * One-To-Many without JOIN table
	 */
	@RequestMapping("/uuid3")
	@ResponseBody
	public void getUUID3() {

		Team team = new Team();
		Player p1 = new Player();
		Player p2 = new Player();

		teamRepository.save(team);
		team.setPlayers(Arrays.asList(new Player[]{p2}));

		team.setName("t1");
		p1.setNickName("p1");
		p1.setTeam(team);
		p2.setNickName("p2");
		p2.setTeam(team);
		teamRepository.save(team);
	}

	@RequestMapping("/uuidname")
	@ResponseBody
	public Contact getUUIDWithName(
			@RequestParam(name = "name", defaultValue = "") String name) {
		List<Contact> cts = repository.findByName(name);
		return cts.isEmpty() ? null : cts.get(0);
	}

	@RequestMapping("/uuid/{id}")
	@ResponseBody
	public String getUUIDWithId(@PathVariable("id") String id) {
		return id + UUID.randomUUID().toString();
	}

}


text:
import uniq from 'lodash/uniq';
import Migration from '../libs/Migration';

export default class extends Migration {
  name = 'Create Collections';

  getCollectionNames() {
    return uniq(
      Object.keys(this.modules.get('oors.mongodb').repositories).map(repositoryName =>
        this.getCollectionName(repositoryName),
      ),
    );
  }

  async up() {
    await Promise.all(this.getCollectionNames().map(name => this.createCollection(name)));
  }

  async down() {
    return Promise.all(this.getCollectionNames().map(name => this.dropCollection(name)));
  }
}


text:
package com.farwolf.weex.module;

import android.graphics.Color;
import android.view.View;

import com.farwolf.util.StringUtil;
import com.farwolf.weex.base.WXModuleBase;
import com.farwolf.weex.util.Weex;
import com.taobao.weex.annotation.JSMethod;
import com.taobao.weex.bridge.JSCallback;

/**
 * Created by zhengjiangrong on 2017/5/10.
 */

public class WXNavBarModule extends WXModuleBase {

    @JSMethod
    public void setTitle(String title)
    {

         if(getTitleBar()!=null)
         getTitleBar().setTitle(title);
    }

    @JSMethod
    public void setTitleColor(String color)
    {
        if(getTitleBar()!=null)
        getTitleBar().title.setTextColor(Color.parseColor(color));
    }

    @JSMethod
    public void setBack(boolean back)
    {
        if(getTitleBar()==null)
            return;
           if(back)
           {
               getTitleBar().setBack();
           }
           else
           {
               getTitleBar().leftview.setVisibility(View.GONE);

           }
    }

    @JSMethod
    public void hide()
    {
        if(getTitleBar()==null)
            return;
        getTitleBar().setVisibility(View.GONE);
    }

    @JSMethod
    public void show()
    {
        if(getTitleBar()==null)
            return;
        getTitleBar().setVisibility(View.VISIBLE);
    }

    @JSMethod
    public void setBackgroundColor(String color)
    {
        if(getTitleBar()==null)
            return;
        getTitleBar().layout.setBackgroundColor(Color.parseColor(color));
    }

    @JSMethod
    public void setRightText(String text,final JSCallback callback)
    {
        getTitleBar().setRightText(text);
        getTitleBar().setRightClick(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                callback.invokeAndKeepAlive(null);
            }
        });
    }

    @JSMethod
    public void setLeftText(String text)
    {
        if(getTitleBar()==null)
            return;
        getTitleBar().setLeftText(text);
    }

    @JSMethod
    public void setRightImage(String src,final JSCallback callback)
    {
        if(getTitleBar()==null)
            return;
        getTitleBar().rightview.setVisibility(View.VISIBLE);
        getTitleBar().right_image.setVisibility(View.VISIBLE);
        getTitleBar().setRightClick(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                callback.invokeAndKeepAlive(null);
            }
        });
        src=StringUtil.getRealUrl(this.mWXSDKInstance.getBundleUrl(),src);

        Weex.downloadImg(src, getTitleBar().right_image,this.mWXSDKInstance.getContext());
    }

}


text:
[![Build status](https://img.shields.io/github/workflow/status/circe/circe-benchmarks/Continuous%20Integration.svg)](https://github.com/circe/circe-benchmarks/actions)
[![Coverage status](https://img.shields.io/codecov/c/github/circe/circe-benchmarks/master.svg)](https://codecov.io/github/circe/circe-benchmarks)
[![Gitter](https://img.shields.io/badge/gitter-join%20chat-green.svg)](https://gitter.im/circe/circe)

This project provides benchmarks comparing the decoding and encoding performance of [circe][circe] with other open source JSON libraries.

## Running benchmarks

See [Benchmark.scala](src/main/scala/io/circe/benchmarks/Benchmark.scala) for the benchmark definitions.

The following commands will run the individual benchmarks:
```bash
sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 io.circe.benchmarks.ReadingBenchmark"
sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 io.circe.benchmarks.WritingBenchmark"
```

## Results

Here are reading and writing results for circe 0.12.0-M4 on Scala 2.13.0 against Argonaut, JSON4S, Play JSON,
and Spray. The `Foos` benchmarks measure encoding and decoding a relatively complex map of case classes with several
members, while the `Ints` benchmarks work with a list of integers.

```
[info] Benchmark                           Mode  Cnt      Score      Error  Units

[info] ReadingBenchmark.readFoosArgonaut  thrpt   20    896.936 ±   16.620  ops/s
[info] ReadingBenchmark.readFoosCirce     thrpt   20   3297.492 ±   71.973  ops/s
[info] ReadingBenchmark.readFoosJson4s    thrpt   20   1153.128 ±   32.758  ops/s
[info] ReadingBenchmark.readFoosJsoniter  thrpt   20  11847.213 ±  423.737  ops/s
[info] ReadingBenchmark.readFoosPlay      thrpt   20   1471.093 ±   40.434  ops/s
[info] ReadingBenchmark.readFoosSpray     thrpt   20   2451.934 ±   57.285  ops/s

[info] ReadingBenchmark.readIntsArgonaut  thrpt   20   7533.894 ±  370.602  ops/s
[info] ReadingBenchmark.readIntsCirce     thrpt   20  16767.628 ±   68.654  ops/s
[info] ReadingBenchmark.readIntsJson4s    thrpt   20   7671.447 ±  182.798  ops/s
[info] ReadingBenchmark.readIntsJsoniter  thrpt   20  60861.281 ± 9193.342  ops/s
[info] ReadingBenchmark.readIntsPlay      thrpt   20   8048.223 ±   99.219  ops/s
[info] ReadingBenchmark.readIntsSpray     thrpt   20  17832.592 ±  277.434  ops/s

---

Benchmark                            Mode  Cnt      Score     Error  Units
ReadingBenchmark.readFoosArgonaut   thrpt   50   1368.041 ±  12.487  ops/s
ReadingBenchmark.readFoosCirce      thrpt   50   4067.121 ±  10.111  ops/s
ReadingBenchmark.readFoosJson4s     thrpt   50   1213.355 ±  20.355  ops/s
ReadingBenchmark.readFoosPlay       thrpt   50   1143.173 ±   7.156  ops/s
ReadingBenchmark.readFoosSpray      thrpt   50   3001.075 ±  12.522  ops/s

ReadingBenchmark.readIntsArgonaut   thrpt   50   8742.412 ±  53.824  ops/s
ReadingBenchmark.readIntsCirce      thrpt   50  18082.714 ±  38.067  ops/s
ReadingBenchmark.readIntsJson4s     thrpt   50   6382.611 ± 162.444  ops/s
ReadingBenchmark.readIntsPlay       thrpt   50   4646.744 ±  26.968  ops/s
ReadingBenchmark.readIntsSpray      thrpt   50  18080.313 ± 194.604  ops/s

Benchmark                            Mode  Cnt      Score     Error  Units
WritingBenchmark.writeFoosArgonaut  thrpt   50   2334.392 ±  47.225  ops/s
WritingBenchmark.writeFoosCirce     thrpt   50   4263.396 ±  92.005  ops/s
WritingBenchmark.writeFoosJson4s    thrpt   50   1633.143 ±   5.642  ops/s
WritingBenchmark.writeFoosPlay      thrpt   50   2177.584 ±   3.430  ops/s
WritingBenchmark.writeFoosSpray     thrpt   50   3588.773 ±  11.324  ops/s

WritingBenchmark.writeIntsArgonaut  thrpt   50  17805.687 ± 463.906  ops/s
WritingBenchmark.writeIntsCirce     thrpt   50  37433.364 ± 146.814  ops/s
WritingBenchmark.writeIntsJson4s    thrpt   50   8180.624 ±  32.511  ops/s
WritingBenchmark.writeIntsPlay      thrpt   50   4011.664 ± 118.561  ops/s
WritingBenchmark.writeIntsSpray     thrpt   50  18803.171 ±  66.265  ops/s
```

(Note that "reading" here includes both parsing and decoding, while "writing" is encoding and printing. It's also
possible to run e.g. decoding or encoding benchmarks individually; see the benchmark source for details.)

## Contributors and participation

All circe projects support the [Typelevel][typelevel] [code of conduct][code-of-conduct] and we want
all of their channels (Gitter, GitHub, etc.) to be welcoming environments for everyone.

Please see the [circe contributors' guide][contributing] for details on how to submit a pull
request.

## License

circe-benchmarks is licensed under the **[Apache License, Version 2.0][apache]**
(the "License"); you may not use this software except in compliance with the
License.

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

[apache]: http://www.apache.org/licenses/LICENSE-2.0
[circe]: https://github.com/circe/circe
[code-of-conduct]: http://typelevel.org/conduct.html
[contributing]: https://circe.github.io/circe/contributing.html
[typelevel]: http://typelevel.org/


text:
package net.burakince.supplymanager.client;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.user.client.DOM;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.ui.VTextField;
import com.vaadin.shared.ui.Connect;

import net.burakince.supplymanager.ResetButtonForTextField;

/**
 * Client side implementation of {@link ResetButtonForTextField}.
 *
 * @see Extending components in Vaadin 7
 */
@SuppressWarnings("serial")
@Connect(ResetButtonForTextField.class)
public class ResetButtonForTextFieldConnector extends AbstractExtensionConnector implements KeyUpHandler, AttachEvent.Handler {

	public static final String CLASSNAME = "resetbuttonfortextfield";
	private VTextField textField;
	private Element resetButtonElement;

	@Override
	protected void extend(ServerConnector serverConnector) {
		serverConnector.addStateChangeHandler(new StateChangeEvent.StateChangeHandler() {
					@Override
					public void onStateChanged(StateChangeEvent stateChangeEvent) {
						Scheduler.get().scheduleDeferred(
								new Scheduler.ScheduledCommand() {
									@Override
									public void execute() {
										updateResetButtonVisibility();
									}
								});
					}
				});

		textField = (VTextField) ((ComponentConnector) serverConnector).getWidget();
		textField.addStyleName(CLASSNAME + "-textfield");

		resetButtonElement = DOM.createDiv();
		resetButtonElement.addClassName(CLASSNAME + "-resetbutton");

		textField.addAttachHandler(this);
		textField.addKeyUpHandler(this);
	}

	private void updateResetButtonVisibility() {
		if (textField.getValue().isEmpty()
				|| textField.getStyleName().contains("v-textfield-prompt")) {
			resetButtonElement.getStyle().setDisplay(Style.Display.NONE);
		} else {
			resetButtonElement.getStyle().clearDisplay();
		}
	}

	public native void addResetButtonClickListener(Element el)
	/*-{
	    var self = this;
	    el.onclick = $entry(function () {
	        self.@net.burakince.supplymanager.client.ResetButtonForTextFieldConnector::clearTextField()();
	    });
	}-*/;

	public native void removeResetButtonClickListener(Element el)
	/*-{
	    el.onclick = null;
	}-*/;

	@Override
	public void onKeyUp(KeyUpEvent keyUpEvent) {
		updateResetButtonVisibility();
	}

	@Override
	public void onAttachOrDetach(AttachEvent attachEvent) {
		if (attachEvent.isAttached()) {
			textField.getElement().getParentElement().insertAfter(resetButtonElement, textField.getElement());
			updateResetButtonVisibility();
			addResetButtonClickListener(resetButtonElement);
		} else {
			Element parentElement = resetButtonElement.getParentElement();
			if (parentElement != null) {
				parentElement.removeChild(resetButtonElement);
			}
			removeResetButtonClickListener(resetButtonElement);
		}
	}

	private void clearTextField() {
		textField.setValue("");
		textField.valueChange(true);
		updateResetButtonVisibility();
		textField.getElement().focus();
	}

}


text:
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta

def extractnumber(text, lang="en-us"):

    """Takes in a string and extracts a number.
    Args:
        text (str): the string to extract a number from
        lang (str): the code for the language text is in
    Returns:
        (str): The number extracted or the original text.
    """

    lang_lower = str(lang).lower()
    if lang_lower.startswith("en"):
        # return extractnumber_en(text, remove_articles)
        return extractnumber_en(text)

    # TODO: Normalization for other languages
    return text

def extract_datetime(text, anchorDate=None, lang="en-us"):

    """
    Parsing function that extracts date and time information
    from sentences. Parses many of the common ways that humans
    express dates and times. Includes relative dates like "5 days from today".

    Vague terminology are given arbitrary values, like:
        - morning = 8 AM
        - afternoon = 3 PM
        - evening = 7 PM

    If a time isn't supplied, the function defaults to 12 AM

    Args:
        str (string): the text to be normalized
        anchortDate (:obj:`datetime`, optional): the date to be used for
            relative dating (for example, what does "tomorrow" mean?).
            Defaults to the current date
            (acquired with datetime.datetime.now())
        lang (string): the language of the sentence(s)

    Returns:
        [:obj:`datetime`, :obj:`str`]: 'datetime' is the extracted date
            as a datetime object. Times are represented in 24 hour notation.
            'leftover_string' is the original phrase with all date and time
            related keywords stripped out. See examples for further
            clarification

            Returns 'None' if no date was extracted.

    Examples:

        >>> extract_datetime(
        ... "What is the weather like the day after tomorrow?",
        ... datetime(2017, 06, 30, 00, 00)
        ... )
        [datetime.datetime(2017, 7, 2, 0, 0), 'what is weather like']

        >>> extract_datetime(
        ... "Set up an appointment 2 weeks from Sunday at 5 pm",
        ... datetime(2016, 02, 19, 00, 00)
        ... )
        [datetime.datetime(2016, 3, 6, 17, 0), 'set up appointment']
    """

    lang_lower = str(lang).lower()

    if lang_lower.startswith("en"):
        return extract_datetime_en(text, anchorDate)

    return text

def is_numeric(input_str):
    """
    Takes in a string and tests to see if it is a number.
    Args:
        text (str): string to test if a number
    Returns:
        (bool): True if a number, else False

    """

    try:
        float(input_str)
        return True
    except ValueError:
        return False

def extractnumber_en(text):
    """
    This function prepares the given text for parsing by making
    numbers consistent, getting rid of contractions, etc.
    Args:
        text (str): the string to normalize
    Returns:
        (int) or (float): The value of extracted number

    """
    aWords = text.split()
    aWords = [word for word in aWords if word not in ["the", "a", "an"]]
    andPass = False
    valPreAnd = False
    val = False
    count = 0
    while count < len(aWords):
        word = aWords[count]
        if is_numeric(word):
            # if word.isdigit():            # doesn't work with decimals
            val = float(word)
        elif word == "first":
            val = 1
        elif word == "second":
            val = 2
        elif isFractional(word):
            val = isFractional(word)
        else:
            if word == "one":
                val = 1
            elif word == "two":
                val = 2
            elif word == "three":
                val = 3
            elif word == "four":
                val = 4
            elif word == "five":
                val = 5
            elif word == "six":
                val = 6
            elif word == "seven":
                val = 7
            elif word == "eight":
                val = 8
            elif word == "nine":
                val = 9
            elif word == "ten":
                val = 10
            if val:
                if count < (len(aWords) - 1):
                    wordNext = aWords[count+1]
                else:
                    wordNext = ""
                valNext = isFractional(wordNext)

                if valNext:
                    val = val * valNext
                    aWords[count+1] = ""

        # if val == False:
        if not val:
            # look for fractions like "2/3"
            aPieces = word.split('/')
            # if (len(aPieces) == 2 and is_numeric(aPieces[0])
            #   and is_numeric(aPieces[1])):
            if look_for_fractions(aPieces):
                val = float(aPieces[0]) / float(aPieces[1])
            elif andPass:
                # added to value, quit here
                val = valPreAnd
                break
            else:
                count += 1
                continue

        aWords[count] = ""

        if (andPass):
            aWords[count-1] = ''     # remove "and"
            val += valPreAnd
        elif count+1 < len(aWords) and aWords[count+1] == 'and':
            andPass = True
            valPreAnd = val
            val = False
            count += 2
            continue
        elif count+2 < len(aWords) and aWords[count+2] == 'and':
            andPass = True
            valPreAnd = val
            val = False
            count += 3
            continue

        break

    # if val == False:
    if not val:
        return False

    # Return the $str with the number related words removed
    # (now empty strings, so strlen == 0)
    aWords = [word for word in aWords if len(word) > 0]
    text = ' '.join(aWords)

    return val

def extract_datetime_en(str, currentDate=None):

    def clean_string(str):
        # cleans the input string of unneeded punctuation and capitalization
        # among other things
        str = str.lower().replace('?', '').replace('.', '').replace(',', '')\
            .replace(' the ', ' ').replace(' a ', ' ').replace(' an ', ' ')
        wordList = str.split()
        for idx, word in enumerate(wordList):
            word = word.replace("'s", "")

            ordinals = ["rd", "st", "nd", "th"]
            if word[0].isdigit():
                for ord in ordinals:
                    if ord in word:
                        word = word.replace(ord, "")
            wordList[idx] = word

        return wordList

    def date_found():
        return found or \
            (
                datestr != "" or timeStr != "" or
                yearOffset != 0 or monthOffset != 0 or
                dayOffset is True or hrOffset != 0 or
                hrAbs != 0 or minOffset != 0 or
                minAbs != 0 or secOffset != 0
            )

    if str == "":
        return None
    if currentDate is None:
        currentDate = datetime.now()

    found = False
    daySpecified = False
    dayOffset = False
    monthOffset = 0
    yearOffset = 0
    dateNow = currentDate
    today = dateNow.strftime("%w")
    currentYear = dateNow.strftime("%Y")
    fromFlag = False
    datestr = ""
    hasYear = False
    timeQualifier = ""

    timeQualifiersList = ['morning', 'afternoon', 'evening']
    markers = ['at', 'in', 'on', 'by', 'this', 'around', 'for', 'of']
    days = ['monday', 'tuesday', 'wednesday',
            'thursday', 'friday', 'saturday', 'sunday']
    months = ['january', 'february', 'march', 'april', 'may', 'june',
              'july', 'august', 'september', 'october', 'november', 'december']
    monthsShort = ['jan', 'feb', 'mar', 'apr', 'may', 'june', 'july', 'aug',
                   'sept', 'oct', 'nov', 'dec']

    words = clean_string(str)

    for idx, word in enumerate(words):
        if word == "":
            continue
        wordPrevPrev = words[idx-2] if idx > 1 else ""
        wordPrev = words[idx-1] if idx > 0 else ""
        wordNext = words[idx+1] if idx+1 < len(words) else ""
        wordNextNext = words[idx+2] if idx+2 < len(words) else ""

        # this isn't in clean string because I don't want to save back to words
        word = word.rstrip('s')
        start = idx
        used = 0
        # save timequalifier for later
        if word in timeQualifiersList:
            timeQualifier = word
            # parse today, tomorrow, day after tomorrow
        elif word == "today" and not fromFlag:
            dayOffset = 0
            used += 1
        elif word == "tomorrow" and not fromFlag:
            dayOffset = 1
            used += 1
        elif (word == "day" and
                wordNext == "after" and
                wordNextNext == "tomorrow" and
                not fromFlag and
                not wordPrev[0].isdigit()):
            dayOffset = 2
            used = 3
            if wordPrev == "the":
                start -= 1
                used += 1
            # parse 5 days, 10 weeks, last week, next week
        elif word == "day":
            if wordPrev[0].isdigit():
                dayOffset += int(wordPrev)
                start -= 1
                used = 2
        elif word == "week" and not fromFlag:
            if wordPrev[0].isdigit():
                dayOffset += int(wordPrev) * 7
                start -= 1
                used = 2
            elif wordPrev == "next":
                dayOffset = 7
                start -= 1
                used = 2
            elif wordPrev == "last":
                dayOffset = -7
                start -= 1
                used = 2
            # parse 10 months, next month, last month
        elif word == "month" and not fromFlag:
            if wordPrev[0].isdigit():
                monthOffset = int(wordPrev)
                start -= 1
                used = 2
            elif wordPrev == "next":
                monthOffset = 1
                start -= 1
                used = 2
            elif wordPrev == "last":
                monthOffset = -1
                start -= 1
                used = 2
            # parse 5 years, next year, last year
        elif word == "year" and not fromFlag:
            if wordPrev[0].isdigit():
                yearOffset = int(wordPrev)
                start -= 1
                used = 2
            elif wordPrev == "next":
                yearOffset = 1
                start -= 1
                used = 2
            elif wordPrev == "last":
                yearOffset = -1
                start -= 1
                used = 2
            # parse Monday, Tuesday, etc., and next Monday,
            # last Tuesday, etc.
        elif word in days and not fromFlag:
            d = days.index(word)
            dayOffset = (d+1)-int(today)
            used = 1
            if dayOffset < 0:
                dayOffset += 7
            if wordPrev == "next":
                dayOffset += 7
                used += 1
                start -= 1
            elif wordPrev == "last":
                dayOffset -= 7
                used += 1
                start -= 1
            # parse 15 of July, June 20th, Feb 18, 19 of February
        elif word in months or word in monthsShort and not fromFlag:
            try:
                m = months.index(word)
            except ValueError:
                m = monthsShort.index(word)
            used += 1
            datestr = months[m]
            if wordPrev[0].isdigit() or \
                    (wordPrev == "of" and wordPrevPrev[0].isdigit()):
                if wordPrev == "of" and wordPrevPrev[0].isdigit():
                    datestr += " " + words[idx-2]
                    used += 1
                    start -= 1
                else:
                    datestr += " " + wordPrev
                start -= 1
                used += 1
                if wordNext and wordNext[0].isdigit():
                    datestr += " " + wordNext
                    used += 1
                    hasYear = True
                else:
                    hasYear = False

            elif wordNext and wordNext[0].isdigit():
                datestr += " " + wordNext
                used += 1
                if wordNextNext and wordNextNext[0].isdigit():
                    datestr += " " + wordNextNext
                    used += 1
                    hasYear = True
                else:
                    hasYear = False
        # parse 5 days from tomorrow, 10 weeks from next thursday,
        # 2 months from July
        validFollowups = days + months + monthsShort
        validFollowups.append("today")
        validFollowups.append("tomorrow")
        validFollowups.append("next")
        validFollowups.append("last")
        validFollowups.append("now")
        if (word == "from" or word == "after") and wordNext in validFollowups:
            used = 2
            fromFlag = True
            if wordNext == "tomorrow":
                dayOffset += 1
            elif wordNext in days:
                d = days.index(wordNext)
                tmpOffset = (d+1)-int(today)
                used = 2
                if tmpOffset < 0:
                    tmpOffset += 7
                dayOffset += tmpOffset
            elif wordNextNext and wordNextNext in days:
                d = days.index(wordNextNext)
                tmpOffset = (d+1)-int(today)
                used = 3
                if wordNext == "next":
                    tmpOffset += 7
                    used += 1
                    start -= 1
                elif wordNext == "last":
                    tmpOffset -= 7
                    used += 1
                    start -= 1
                dayOffset += tmpOffset
        if used > 0:
            if start-1 > 0 and words[start-1] == "this":
                start -= 1
                used += 1

            for i in range(0, used):
                words[i+start] = ""

            if (start-1 >= 0 and words[start-1] in markers):
                words[start-1] = ""
            found = True
            daySpecified = True

    # parse time
    timeStr = ""
    hrOffset = 0
    minOffset = 0
    secOffset = 0
    hrAbs = 0
    minAbs = 0
    military = False

    for idx, word in enumerate(words):
        if word == "":
            continue

        wordPrevPrev = words[idx-2] if idx > 1 else ""
        wordPrev = words[idx-1] if idx > 0 else ""
        wordNext = words[idx+1] if idx+1 < len(words) else ""
        wordNextNext = words[idx+2] if idx+2 < len(words) else ""
        # parse noon, midnight, morning, afternoon, evening
        used = 0
        if word == "noon":
            hrAbs = 12
            used += 1
        elif word == "midnight":
            hrAbs = 0
            used += 1
        elif word == "morning":
            if hrAbs == 0:
                hrAbs = 8
            used += 1
        elif word == "afternoon":
            if hrAbs == 0:
                hrAbs = 15
            used += 1
        elif word == "evening":
            if hrAbs == 0:
                hrAbs = 19
            used += 1
            # parse half an hour, quarter hour
        elif word == "hour" and \
                (wordPrev in markers or wordPrevPrev in markers):
            if wordPrev == "half":
                minOffset = 30
            elif wordPrev == "quarter":
                minOffset = 15
            elif wordPrevPrev == "quarter":
                minOffset = 15
                if idx > 2 and words[idx-3] in markers:
                    words[idx-3] = ""
                words[idx-2] = ""
            else:
                hrOffset = 1
            if wordPrevPrev in markers:
                words[idx-2] = ""
            words[idx-1] = ""
            used += 1
            hrAbs = -1
            minAbs = -1
            # parse 5:00 am, 12:00 p.m., etc
        elif word[0].isdigit():
            isTime = True
            strHH = ""
            strMM = ""
            remainder = ""
            if ':' in word:
                # parse colons
                # "3:00 in the morning"
                stage = 0
                length = len(word)
                for i in range(length):
                    if stage == 0:
                        if word[i].isdigit():
                            strHH += word[i]
                        elif word[i] == ":":
                            stage = 1
                        else:
                            stage = 2
                            i -= 1
                    elif stage == 1:
                        if word[i].isdigit():
                            strMM += word[i]
                        else:
                            stage = 2
                            i -= 1
                    elif stage == 2:
                        remainder = word[i:].replace(".", "")
                        break
                if remainder == "":
                    nextWord = wordNext.replace(".", "")
                    if nextWord == "am" or nextWord == "pm":
                        remainder = nextWord
                        used += 1
                    elif wordNext == "in" and wordNextNext == "the" and \
                            words[idx+3] == "morning":
                        reaminder = "am"
                        used += 3
                    elif wordNext == "in" and wordNextNext == "the" and \
                            words[idx+3] == "afternoon":
                        remainder = "pm"
                        used += 3
                    elif wordNext == "in" and wordNextNext == "the" and \
                            words[idx+3] == "evening":
                        remainder = "pm"
                        used += 3
                    elif wordNext == "in" and wordNextNext == "morning":
                        remainder = "am"
                        used += 2
                    elif wordNext == "in" and wordNextNext == "afternoon":
                        remainder = "pm"
                        used += 2
                    elif wordNext == "in" and wordNextNext == "evening":
                        remainder = "pm"
                        used += 2
                    elif wordNext == "this" and wordNextNext == "morning":
                        remainder = "am"
                        used = 2
                    elif wordNext == "this" and wordNextNext == "afternoon":
                        remainder = "pm"
                        used = 2
                    elif wordNext == "this" and wordNextNext == "evening":
                        remainder = "pm"
                        used = 2
                    elif wordNext == "at" and wordNextNext == "night":
                        if strHH > 5:
                            remainder = "pm"
                        else:
                            remainder = "am"
                        used += 2
                    else:
                        if timeQualifier != "":
                            military = True
                            if strHH <= 12 and \
                                    (timeQualifier == "evening" or
                                        timeQualifier == "afternoon"):
                                strHH += 12
            else:
                # try to parse # s without colons
                # 5 hours, 10 minutes etc.
                length = len(word)
                strNum = ""
                remainder = ""
                for i in range(length):
                    if word[i].isdigit():
                        strNum += word[i]
                    else:
                        remainder += word[i]

                if remainder == "":
                    remainder = wordNext.replace(".", "").lstrip().rstrip()

                if (
                        remainder == "pm" or
                        wordNext == "pm" or
                        remainder == "p.m." or
                        wordNext == "p.m."):
                    strHH = strNum
                    remainder = "pm"
                    used = 1
                elif(
                        remainder == "am" or
                        wordNext == "am" or
                        remainder == "a.m." or
                        wordNext == "a.m."):
                    strHH = strNum
                    remainder = "am"
                    used = 1
                else:
                    if wordNext == "pm" or wordNext == "p.m.":
                        strHH = strNum
                        reaminder = "pm"
                        used = 1
                    elif wordNext == "am" or wordNext == "a.m.":
                        strHH = strNum
                        remainder = "am"
                        used = 1
                    elif(
                            int(word) > 100 and
                            (
                                wordPrev == "o" or
                                wordPrev == "oh"
                            )):
                        # 0800 hours (pronounced oh-eight-hundred)
                        strHH = int(word)/100
                        strMM = int(word) - strHH*100
                        military = True
                        if wordNext == "hours":
                            used += 1
                    elif(
                            wordNext == "hours" and
                            word[0] != '0' and
                            (
                                int(word) < 100 and
                                int(word) > 2400
                            )):
                        # ignores military time
                        # "in 3 hours"
                        hrOffset = int(word)
                        used = 2
                        isTime = False
                        hrAbs = -1
                        minAbs = -1

                    elif wordNext == "minutes":
                        # "in 10 minutes"
                        minOffset = int(word)
                        used = 2
                        isTime = False
                        hrAbs = -1
                        minAbs = -1
                    elif wordNext == "seconds":
                        # in 5 seconds
                        secOffset = int(word)
                        used = 2
                        isTime = False
                        hrAbs = -1
                        minAbs = -1
                    elif int(word) > 100:
                        strHH = int(word)/100
                        strMM = int(word) - strHH*100
                        military = True
                        if wordNext == "hours":
                            used += 1
                    elif wordNext[0].isdigit():
                        strHH = word
                        strMM = wordNext
                        military = True
                        used += 1
                        if wordNextNext == "hours":
                            used += 1
                    elif(
                            wordNext == "" or wordNext == "o'clock" or
                            (
                                wordNext == "in" and
                                (
                                    wordNextNext == "the" or
                                    wordNextNext == timeQualifier
                                )
                            )):
                        strHH = word
                        strMM = 00
                        if wordNext == "o'clock":
                            used += 1
                        if wordNext == "in" or wordNextNext == "in":
                            used += (1 if wordNext == "in" else 2)
                            if (
                                    wordNextNext and
                                    wordNextNext in timeQualifier or
                                    (words[words.index(wordNextNext)+1] and
                                    words[words.index(wordNextNext)+1] in timeQualifier)  # noqa
                                ):
                                if (
                                        wordNextNext == "afternoon" or
                                        (len(words) > words.index(wordNextNext) + 1 and  # noqa
                                        words[words.index(wordNextNext)+1] == "afternoon")  # noqa
                                    ):
                                    remainder = "pm"
                                if (
                                        wordNextNext == "evening" or
                                        (len(words) > (words.index(wordNextNext) + 1) and  # noqa
                                        words[words.index(wordNextNext)+1] == "evening")  # noqa
                                    ):
                                    remainder = "pm"
                                if (
                                        wordNextNext == "morning" or
                                        (len(words) > words.index(wordNextNext) + 1 and  # noqa
                                        words[words.index(wordNextNext)+1] == "morning")  # noqa
                                    ):
                                    remainder = "am"
                        if timeQualifier != "":
                            military = True
                    else:
                        isTime = False

            strHH = int(strHH) if strHH else 0
            strMM = int(strMM) if strMM else 0
            strHH = strHH+12 if remainder == "pm" and strHH < 12 else strHH
            strHH = strHH-12 if remainder == "am" and strHH >= 12 else strHH
            if strHH > 24 or strMM > 59:
                isTime = False
                used = 0
            if isTime:
                hrAbs = strHH * 1
                minAbs = strMM * 1
                used += 1
        if used > 0:
            # removed parsed words from the sentence
            for i in range(used):
                words[idx + i] = ""

            if wordPrev == "o" or wordPrev == "oh":
                words[words.index(wordPrev)] = ""

            if wordPrev == "early":
                hrOffset = -1
                words[idx-1] = ""
                idx -= 1
            elif wordPrev == "late":
                hrOffset = 1
                words[idx-1] = ""
                idx -= 1
            if idx > 0 and wordPrev in markers:
                words[idx-1] = ""
            if idx > 1 and wordPrevPrev in markers:
                words[idx-2] = ""

            idx += used-1
            found = True

    # check that we found a date
    if not date_found:
        return None

    if dayOffset is False:
        dayOffset = 0

    # perform date manipulation

    extractedDate = dateNow
    extractedDate = extractedDate.replace(microsecond=0,
                                          second=0,
                                          minute=0,
                                          hour=0)
    if datestr != "":
        temp = datetime.strptime(datestr, "%B %d")
        if not hasYear:
            temp = temp.replace(year=extractedDate.year)
            if extractedDate < temp:
                extractedDate = extractedDate.replace(year=int(currentYear),
                                                      month=int(temp.strftime("%m")),  # noqa
                                                      day=int(temp.strftime("%d")))  # noqa
            else:
                extractedDate = extractedDate.replace(year=int(currentYear)+1,
                                                      month=int(temp.strftime("%m")),  # noqa
                                                      day=int(temp.strftime("%d")))  # noqa
        else:
            extractedDate = extractedDate.replace(year=int(temp.strftime("%Y")),  # noqa
                                                 month=int(temp.strftime("%m")),  # noqa
                                                 day=int(temp.strftime("%d")))

    if timeStr != "":
        temp = datetime(timeStr)
        extractedDate = extractedDate.replace(hour=temp.strftime("%H"),
                                              minute=temp.strftime("%M"),
                                              second=temp.strftime("%S"))

    if yearOffset != 0:
        extractedDate = extractedDate + relativedelta(years=yearOffset)
    if monthOffset != 0:
        extractedDate = extractedDate + relativedelta(months=monthOffset)
    if dayOffset != 0:
        extractedDate = extractedDate + relativedelta(days=dayOffset)
    if hrAbs != -1 and minAbs != -1:

        extractedDate = extractedDate + relativedelta(hours=hrAbs,
                                                      minutes=minAbs)
        if (hrAbs != 0 or minAbs != 0) and datestr == "":
            if not daySpecified and dateNow > extractedDate:
                extractedDate = extractedDate + relativedelta(days=1)
    if hrOffset != 0:
        extractedDate = extractedDate + relativedelta(hours=hrOffset)
    if minOffset != 0:
        extractedDate = extractedDate + relativedelta(minutes=minOffset)
    if secOffset != 0:
        extractedDate = extractedDate + relativedelta(seconds=secOffset)
    for idx, word in enumerate(words):
        if words[idx] == "and" and words[idx-1] == "" and words[idx+1] == "":
            words[idx] = ""

    resultStr = " ".join(words)
    resultStr = ' '.join(resultStr.split())
    return [extractedDate, resultStr]

def look_for_fractions(split_list):
    """"
    This function takes a list made by fraction & determines if a fraction.

    Args:
        split_list (list): list created by splitting on '/'
    Returns:
        (bool): False if not a fraction, otherwise True

    """

    if len(split_list) == 2:
        if is_numeric(split_list[0]) and is_numeric(split_list[1]):
            return True

    return False

def isFractional(input_str):
    """
    This function takes the given text and checks if it is a fraction.

    Args:
        text (str): the string to check if fractional
    Returns:
        (bool) or (float): False if not a fraction, otherwise the fraction

    """
    if input_str.endswith('s', -1):
        input_str = input_str[:len(input_str)-1]		# e.g. "fifths"

    aFrac = ["whole", "half", "third", "fourth", "fifth", "sixth",
             "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"]

    if input_str.lower() in aFrac:
        return 1.0/(aFrac.index(input_str)+1)
    if input_str == "quarter":
        return 1.0/4

    return False

# ==============================================================

def normalize(text, lang="en-us", remove_articles=True):
    """Prepare a string for parsing

    This function prepares the given text for parsing by making
    numbers consistent, getting rid of contractions, etc.
    Args:
        text (str): the string to normalize
        lang (str): the code for the language text is in
        remove_articles (bool): whether to remove articles (like 'a', or 'the')
    Returns:
        (str): The normalized string.
    """

    lang_lower = str(lang).lower()
    if lang_lower.startswith("en"):
        return normalize_en(text, remove_articles)
    elif lang_lower.startswith("es"):
        return normalize_es(text, remove_articles)

    # TODO: Normalization for other languages
    return text

def normalize_en(text, remove_articles):
    """ English string normalization """

    words = text.split()  # this also removed extra spaces
    normalized = ""
    for word in words:
        if remove_articles and word in ["the", "a", "an"]:
            continue

        # Expand common contractions, e.g. "isn't" -> "is not"
        contraction = ["ain't", "aren't", "can't", "could've", "couldn't",
                       "didn't", "doesn't", "don't", "gonna", "gotta",
                       "hadn't", "hasn't", "haven't", "he'd", "he'll", "he's",
                       "how'd", "how'll", "how's", "I'd", "I'll", "I'm",
                       "I've", "isn't", "it'd", "it'll", "it's", "mightn't",
                       "might've", "mustn't", "must've", "needn't", "oughtn't",
                       "shan't", "she'd", "she'll", "she's", "shouldn't",
                       "should've", "somebody's", "someone'd", "someone'll",
                       "someone's", "that'll", "that's", "that'd", "there'd",
                       "there're", "there's", "they'd", "they'll", "they're",
                       "they've", "wasn't", "we'd", "we'll", "we're", "we've",
                       "weren't", "what'd", "what'll", "what're", "what's",
                       "whats",  # technically incorrect but some STT does this
                       "what've", "when's", "when'd", "where'd", "where's",
                       "where've", "who'd", "who'd've", "who'll", "who're",
                       "who's", "who've", "why'd", "why're", "why's", "won't",
                       "won't've", "would've", "wouldn't", "wouldn't've",
                       "y'all", "ya'll", "you'd", "you'd've", "you'll",
                       "y'aint", "y'ain't", "you're", "you've"]
        if word in contraction:
            expansion = ["is not", "are not", "can not", "could have",
                         "could not", "did not", "does not", "do not",
                         "going to", "got to", "had not", "has not",
                         "have not", "he would", "he will", "he is", "how did",
                         "how will", "how is", "I would", "I will", "I am",
                         "I have", "is not", "it would", "it will", "it is",
                         "might not", "might have", "must not", "must have",
                         "need not", "ought not", "shall not", "she would",
                         "she will", "she is", "should not", "should have",
                         "somebody is", "someone would", "someone will",
                         "someone is", "that will", "that is", "that would",
                         "there would", "there are", "there is", "they would",
                         "they will", "they are", "they have", "was not",
                         "we would", "we will", "we are", "we have",
                         "were not", "what did", "what will", "what are",
                         "what is",
                         "what is", "what have", "when is", "when did",
                         "where did", "where is", "where have", "who would",
                         "who would have", "who will", "who are", "who is",
                         "who have", "why did", "why are", "why is",
                         "will not", "will not have", "would have",
                         "would not", "would not have", "you all", "you all",
                         "you would", "you would have", "you will",
                         "you are not", "you are not", "you are", "you have"]
            word = expansion[contraction.index(word)]

        # Convert numbers into digits, e.g. "two" -> "2"
        textNumbers = ["zero", "one", "two", "three", "four", "five", "six",
                       "seven", "eight", "nine", "ten", "eleven", "twelve",
                       "thirteen", "fourteen", "fifteen", "sixteen",
                       "seventeen", "eighteen", "nineteen", "twenty"]
        if word in textNumbers:
            word = str(textNumbers.index(word))

        normalized += " " + word

    return normalized[1:]  # strip the initial space

####################################################################
# Spanish normalization
#
# TODO: numbers greater than 999999
####################################################################

# Undefined articles ["un", "una", "unos", "unas"] can not be supressed,
# in Spanish, "un caballo" means "a horse" or "one horse".
es_articles = ["el", "la", "los", "las"]

es_numbers_xlat = {
    "un": 1,
    "uno": 1,
    "una": 1,
    "dos": 2,
    "tres": 3,
    "cuatro": 4,
    "cinco": 5,
    "seis": 6,
    "siete": 7,
    "ocho": 8,
    "nueve": 9,
    "diez": 10,
    "once": 11,
    "doce": 12,
    "trece": 13,
    "catorce": 14,
    "quince": 15,
    u"dieciséis": 16,
    "diecisiete": 17,
    "dieciocho": 18,
    "diecinueve": 19,
    "veinte": 20,
    "veintiuno": 21,
    u"veintidós": 22,
    u"veintitrés": 23,
    "veinticuatro": 24,
    "veinticinco": 25,
    u"veintiséis": 26,
    "veintisiete": 27,
    "veintiocho": 28,
    "veintinueve": 29,
    "treinta": 30,
    "cuarenta": 40,
    "cincuenta": 50,
    "sesenta": 60,
    "setenta": 70,
    "ochenta": 80,
    "noventa": 90,
    "cien": 100,
    "ciento": 100,
    "doscientos": 200,
    "doscientas": 200,
    "trescientos": 300,
    "trescientas": 300,
    "cuatrocientos": 400,
    "cuatrocientas": 400,
    "quinientos": 500,
    "quinientas": 500,
    "seiscientos": 600,
    "seiscientas": 600,
    "setecientos": 700,
    "setecientas": 700,
    "ochocientos": 800,
    "ochocientas": 800,
    "novecientos": 900,
    "novecientas": 900}

def es_parse(words, i):
    def es_cte(i, s):
        if i < len(words) and s == words[i]:
            return s, i+1
        return None

    def es_number_word(i, mi, ma):
        if i < len(words):
            v = es_numbers_xlat.get(words[i])
            if v and v >= mi and v <= ma:
                return v, i+1
        return None

    def es_number_1_99(i):
        r1 = es_number_word(i, 1, 29)
        if r1:
            return r1

        r1 = es_number_word(i, 30, 90)
        if r1:
            v1, i1 = r1
            r2 = es_cte(i1, "y")
            if r2:
                v2, i2 = r2
                r3 = es_number_word(i2, 1, 9)
                if r3:
                    v3, i3 = r3
                    return v1+v3, i3
            return r1
        return None

    def es_number_1_999(i):
        # [2-9]cientos [1-99]?
        r1 = es_number_word(i, 100, 900)
        if r1:
            v1, i1 = r1
            r2 = es_number_1_99(i1)
            if r2:
                v2, i2 = r2
                return v1+v2, i2
            else:
                return r1

        # [1-99]
        r1 = es_number_1_99(i)
        if r1:
            return r1

        return None

    def es_number(i):
        # check for cero
        r1 = es_number_word(i, 0, 0)
        if r1:
            return r1

        # check for [1-999] (mil [0-999])?
        r1 = es_number_1_999(i)
        if r1:
            v1, i1 = r1
            r2 = es_cte(i1, "mil")
            if r2:
                v2, i2 = r2
                r3 = es_number_1_999(i2)
                if r3:
                    v3, i3 = r3
                    return v1*1000+v3, i3
                else:
                    return v1*1000, i2
            else:
                return r1
        return None

    return es_number(i)

def normalize_es(text, remove_articles):
    """ Spanish string normalization """

    words = text.split()  # this also removed extra spaces

    normalized = ""
    i = 0
    while i < len(words):
        word = words[i]

        if remove_articles and word in es_articles:
            i += 1
            continue

        # Convert numbers into digits
        r = es_parse(words, i)
        if r:
            v, i = r
            normalized += " " + str(v)
            continue

        normalized += " " + word
        i += 1

    return normalized[1:]  # strip the initial space