test_track_rails_client 4.0.0.alpha32 → 4.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +14 -13
- data/Rakefile +6 -4
- data/app/assets/javascripts/testTrack.bundle.min.js +1 -1
- data/app/controllers/concerns/test_track/controller.rb +1 -3
- data/app/models/concerns/test_track/required_options.rb +1 -0
- data/app/models/test_track/ab_configuration.rb +3 -5
- data/app/models/test_track/analytics/mixpanel_client.rb +1 -0
- data/app/models/test_track/analytics/safe_wrapper.rb +1 -0
- data/app/models/test_track/application_identity.rb +1 -0
- data/app/models/test_track/assignment.rb +2 -1
- data/app/models/test_track/config_updater.rb +3 -3
- data/app/models/test_track/fake/split_registry.rb +4 -6
- data/app/models/test_track/job_session.rb +1 -3
- data/app/models/test_track/lazy_visitor_by_identity.rb +8 -4
- data/app/models/test_track/misconfiguration_notifier.rb +1 -0
- data/app/models/test_track/notify_assignment_job.rb +1 -0
- data/app/models/test_track/remote/assignment_event.rb +1 -1
- data/app/models/test_track/remote/fake_server.rb +1 -0
- data/app/models/test_track/remote/identifier.rb +2 -1
- data/app/models/test_track/remote/identifier_type.rb +1 -1
- data/app/models/test_track/remote/split_config.rb +1 -1
- data/app/models/test_track/remote/split_detail.rb +2 -2
- data/app/models/test_track/remote/split_registry.rb +2 -2
- data/app/models/test_track/remote/visitor.rb +2 -2
- data/app/models/test_track/remote/visitor_detail.rb +1 -1
- data/app/models/test_track/split_registry.rb +3 -3
- data/app/models/test_track/threaded_visitor_notifier.rb +6 -8
- data/app/models/test_track/unsynced_assignments_notifier.rb +4 -6
- data/app/models/test_track/variant_calculator.rb +1 -0
- data/app/models/test_track/vary_dsl.rb +4 -0
- data/app/models/test_track/visitor.rb +5 -4
- data/app/models/test_track/web_session.rb +5 -3
- data/app/models/test_track/web_session_visitor_repository.rb +1 -3
- data/config/initializers/set_build_timestamp.rb +1 -0
- data/lib/tasks/test_track_rails_client_tasks.rake +21 -0
- data/lib/test_track.rb +27 -0
- data/lib/test_track_rails_client/engine.rb +4 -2
- data/lib/test_track_rails_client/version.rb +1 -1
- data/vendor/bin/testtrack-cli/testtrack.darwin +0 -0
- data/vendor/bin/testtrack-cli/testtrack.linux +0 -0
- metadata +129 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5c66d9d6a03b2089f12dc29601ef72d3b24a38c2772f719c84a33561d87c38d9
|
4
|
+
data.tar.gz: 6a884499fd36e03da076595c460fd32e5177a1fc8961957d8014a42b3faef8a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13493acef4dfb8e0a74318fa32b8e23636710b07cc9d90544a0d4bea406a41ae69810e78a73323d538b41ba5ee208713dc07c15e387a69fc5c0cb900dc3cf051
|
7
|
+
data.tar.gz: 5175ed66bec77901a9206155da9ff7d6a7e9c0ec10d4d98406a8038e8ad1a14834a226321cda18b5ba5a3ce1355afae4950507fbc8cbd5a68e763ca04dc56799
|
data/README.md
CHANGED
@@ -50,7 +50,7 @@ Set up ENV vars in every environment:
|
|
50
50
|
* `TEST_TRACK_API_URL` - Set this to the URL of your TestTrack instance with your app credentials, e.g. `http://[myapp]:[your new app password]@[your-app-domain]/`
|
51
51
|
|
52
52
|
[your-app-domain] can be
|
53
|
-
* `testtrack.
|
53
|
+
* `testtrack.test`
|
54
54
|
* `localhost:PORT`
|
55
55
|
* `example.org`
|
56
56
|
* etc
|
@@ -72,8 +72,8 @@ If your app doesn't support authentication, set
|
|
72
72
|
|
73
73
|
### Prepare your identity models (optional)
|
74
74
|
|
75
|
-
If your app supports authentication,
|
76
|
-
`User` model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model)
|
75
|
+
If your app supports authentication, you'll need to configure your
|
76
|
+
`User` model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model).
|
77
77
|
|
78
78
|
### Set up the Chrome extension (optional)
|
79
79
|
|
@@ -288,7 +288,7 @@ class BackgroundWorkJob
|
|
288
288
|
end
|
289
289
|
end
|
290
290
|
end
|
291
|
-
```
|
291
|
+
```
|
292
292
|
|
293
293
|
## Tracking visitor logins
|
294
294
|
|
@@ -391,28 +391,29 @@ def notify(message)
|
|
391
391
|
|
392
392
|
### From 3.0 to 4.0
|
393
393
|
|
394
|
-
The contract of custom analytics plugins has changed. Instead of
|
394
|
+
* The contract of custom analytics plugins has changed. Instead of
|
395
395
|
implementing `track_assignment` you now must implement `track`. It's
|
396
396
|
easier and more conventional, though, and takes care of differentiating
|
397
|
-
between
|
397
|
+
between experiment assignments and feature gate experiences, which are
|
398
398
|
no longer recorded server-side.
|
399
399
|
|
400
|
-
You
|
400
|
+
* You must add `self.test_track_identity = :current_user` (or
|
401
401
|
whatever your controller uses as a sign-in identity) to your
|
402
402
|
TestTrack-enabled controllers, or set it to `:none` if your app doesn't
|
403
|
-
support authentication.
|
403
|
+
support authentication. If your app supports authentication, you'll need to configure your
|
404
|
+
user model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model).
|
404
405
|
|
405
|
-
If your
|
406
|
-
user model as a [TestTrack Identity](#varying-app-behavior-from-within-a-model)
|
406
|
+
* TestTrack server [introduced a new endpoint](https://github.com/Betterment/test_track/pull/133) for fetching the split registry that requires a timestamp of when the application was built. This prevents dropped splits from breaking a running application. If you use `rake assets:precompile` in your build pipeline, you're all set. If you don't, you'll need to call `rake test_track:generate_build_timestamp` and ensure that the file `testtrack/build_timestamp` is deployed along with your app.
|
407
407
|
|
408
408
|
### From 2.0 to 3.0
|
409
409
|
|
410
|
-
TestTrack Rails Client no longer manages your Mixpanel cookie. The analytics plugin now provides a callback on `sign_up!` that will allow you to implement this functionality within your application. Please see the [analytics documentation](#analytics) for more details.
|
411
|
-
|
410
|
+
* TestTrack Rails Client no longer manages your Mixpanel cookie. The analytics plugin now provides a callback on `sign_up!` that will allow you to implement this functionality within your application. Please see the [analytics documentation](#analytics) for more details.
|
411
|
+
|
412
|
+
* `TestTrack.analytics#track_assignment` no longer accepts a properties hash as an argument as `mixpanel_distinct_id` is no longer relevant.
|
412
413
|
|
413
414
|
### From 1.x to 1.3
|
414
415
|
|
415
|
-
`TestTrack::Session#log_in!` and `TestTrack:Session#sign_up!` now take a `TestTrack::Identity` instance argument instead of an identity type and identity value.
|
416
|
+
* `TestTrack::Session#log_in!` and `TestTrack:Session#sign_up!` now take a `TestTrack::Identity` instance argument instead of an identity type and identity value.
|
416
417
|
|
417
418
|
## How to Contribute
|
418
419
|
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
14
14
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
15
|
end
|
16
16
|
|
17
|
-
APP_RAKEFILE = File.expand_path(
|
17
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
18
18
|
load 'rails/tasks/engine.rake'
|
19
19
|
|
20
20
|
Bundler::GemHelper.install_tasks
|
@@ -28,12 +28,14 @@ RuboCop::RakeTask.new
|
|
28
28
|
|
29
29
|
desc "Pull the latest versions of all dependencies into the gem for distribution"
|
30
30
|
task :vendor_deps do
|
31
|
-
TEST_TRACK_JS_CLIENT_VERSION = '
|
32
|
-
TEST_TRACK_CLI_VERSION = 'v1.
|
31
|
+
TEST_TRACK_JS_CLIENT_VERSION = '2.0.0-alpha.6'.freeze
|
32
|
+
TEST_TRACK_CLI_VERSION = 'v1.1.3'.freeze
|
33
33
|
|
34
34
|
# Bundle JS client
|
35
|
+
sh 'npm init -y'
|
35
36
|
sh "npm install --no-save test_track_js_client@#{TEST_TRACK_JS_CLIENT_VERSION}"
|
36
|
-
sh 'cp', 'node_modules/test_track_js_client/dist/testTrack.bundle.
|
37
|
+
sh 'cp', 'node_modules/test_track_js_client/dist/testTrack.bundle.js', 'app/assets/javascripts/testTrack.bundle.min.js'
|
38
|
+
sh 'rm package.json'
|
37
39
|
|
38
40
|
# Download testtrack-cli
|
39
41
|
FileUtils.module_eval do
|
@@ -1 +1 @@
|
|
1
|
-
!function(t){var e="object"==typeof exports&&exports,i="object"==typeof module&&module&&module.exports==e&&module,n="object"==typeof global&&global;n.global!==n&&n.window!==n||(t=n);var r=function(t){this.message=t};(r.prototype=new Error).name="InvalidCharacterError";var o=function(t){throw new r(t)},s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",a=/[\t\n\f\r ]/g,u={encode:function(t){t=String(t),/[^\0-\xFF]/.test(t)&&o("The string to be encoded contains characters outside of the Latin1 range.");for(var e,i=t.length%3,n="",r=-1,a=t.length-i;++r<a;)e=(t.charCodeAt(r)<<16)+(t.charCodeAt(++r)<<8)+t.charCodeAt(++r),n+=s.charAt(e>>18&63)+s.charAt(e>>12&63)+s.charAt(e>>6&63)+s.charAt(63&e);return 2==i?(e=(t.charCodeAt(r)<<8)+t.charCodeAt(++r),n+=s.charAt(e>>10)+s.charAt(e>>4&63)+s.charAt(e<<2&63)+"="):1==i&&(e=t.charCodeAt(r),n+=s.charAt(e>>2)+s.charAt(e<<4&63)+"=="),n},decode:function(t){var e=(t=String(t).replace(a,"")).length;e%4==0&&(e=(t=t.replace(/==?$/,"")).length),(e%4==1||/[^+a-zA-Z0-9/]/.test(t))&&o("Invalid character: the string to be decoded is not correctly encoded.");for(var i,n,r=0,u="",f=-1;++f<e;)n=s.indexOf(t.charAt(f)),i=r%4?64*i+n:n,r++%4&&(u+=String.fromCharCode(255&i>>(-2*r&6)));return u},version:"0.1.0"};if("function"==typeof define&&"object"==typeof define.amd&&define.amd)define(function(){return u});else if(e&&!e.nodeType)if(i)i.exports=u;else for(var f in u)u.hasOwnProperty(f)&&(e[f]=u[f]);else t.base64=u}(this),function(t){"use strict";function e(t,e){var i=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(i>>16)<<16|65535&i}function i(t,e){return t<<e|t>>>32-e}function n(t,n,r,o,s,a){return e(i(e(e(n,t),e(o,a)),s),r)}function r(t,e,i,r,o,s,a){return n(e&i|~e&r,t,e,o,s,a)}function o(t,e,i,r,o,s,a){return n(e&r|i&~r,t,e,o,s,a)}function s(t,e,i,r,o,s,a){return n(e^i^r,t,e,o,s,a)}function a(t,e,i,r,o,s,a){return n(i^(e|~r),t,e,o,s,a)}function u(t,i){t[i>>5]|=128<<i%32,t[14+(i+64>>>9<<4)]=i;var n,u,f,c,p,d=1732584193,h=-271733879,l=-1732584194,g=271733878;for(n=0;n<t.length;n+=16)u=d,f=h,c=l,p=g,h=a(h=a(h=a(h=a(h=s(h=s(h=s(h=s(h=o(h=o(h=o(h=o(h=r(h=r(h=r(h=r(h,l=r(l,g=r(g,d=r(d,h,l,g,t[n],7,-680876936),h,l,t[n+1],12,-389564586),d,h,t[n+2],17,606105819),g,d,t[n+3],22,-1044525330),l=r(l,g=r(g,d=r(d,h,l,g,t[n+4],7,-176418897),h,l,t[n+5],12,1200080426),d,h,t[n+6],17,-1473231341),g,d,t[n+7],22,-45705983),l=r(l,g=r(g,d=r(d,h,l,g,t[n+8],7,1770035416),h,l,t[n+9],12,-1958414417),d,h,t[n+10],17,-42063),g,d,t[n+11],22,-1990404162),l=r(l,g=r(g,d=r(d,h,l,g,t[n+12],7,1804603682),h,l,t[n+13],12,-40341101),d,h,t[n+14],17,-1502002290),g,d,t[n+15],22,1236535329),l=o(l,g=o(g,d=o(d,h,l,g,t[n+1],5,-165796510),h,l,t[n+6],9,-1069501632),d,h,t[n+11],14,643717713),g,d,t[n],20,-373897302),l=o(l,g=o(g,d=o(d,h,l,g,t[n+5],5,-701558691),h,l,t[n+10],9,38016083),d,h,t[n+15],14,-660478335),g,d,t[n+4],20,-405537848),l=o(l,g=o(g,d=o(d,h,l,g,t[n+9],5,568446438),h,l,t[n+14],9,-1019803690),d,h,t[n+3],14,-187363961),g,d,t[n+8],20,1163531501),l=o(l,g=o(g,d=o(d,h,l,g,t[n+13],5,-1444681467),h,l,t[n+2],9,-51403784),d,h,t[n+7],14,1735328473),g,d,t[n+12],20,-1926607734),l=s(l,g=s(g,d=s(d,h,l,g,t[n+5],4,-378558),h,l,t[n+8],11,-2022574463),d,h,t[n+11],16,1839030562),g,d,t[n+14],23,-35309556),l=s(l,g=s(g,d=s(d,h,l,g,t[n+1],4,-1530992060),h,l,t[n+4],11,1272893353),d,h,t[n+7],16,-155497632),g,d,t[n+10],23,-1094730640),l=s(l,g=s(g,d=s(d,h,l,g,t[n+13],4,681279174),h,l,t[n],11,-358537222),d,h,t[n+3],16,-722521979),g,d,t[n+6],23,76029189),l=s(l,g=s(g,d=s(d,h,l,g,t[n+9],4,-640364487),h,l,t[n+12],11,-421815835),d,h,t[n+15],16,530742520),g,d,t[n+2],23,-995338651),l=a(l,g=a(g,d=a(d,h,l,g,t[n],6,-198630844),h,l,t[n+7],10,1126891415),d,h,t[n+14],15,-1416354905),g,d,t[n+5],21,-57434055),l=a(l,g=a(g,d=a(d,h,l,g,t[n+12],6,1700485571),h,l,t[n+3],10,-1894986606),d,h,t[n+10],15,-1051523),g,d,t[n+1],21,-2054922799),l=a(l,g=a(g,d=a(d,h,l,g,t[n+8],6,1873313359),h,l,t[n+15],10,-30611744),d,h,t[n+6],15,-1560198380),g,d,t[n+13],21,1309151649),l=a(l,g=a(g,d=a(d,h,l,g,t[n+4],6,-145523070),h,l,t[n+11],10,-1120210379),d,h,t[n+2],15,718787259),g,d,t[n+9],21,-343485551),d=e(d,u),h=e(h,f),l=e(l,c),g=e(g,p);return[d,h,l,g]}function f(t){var e,i="";for(e=0;e<32*t.length;e+=8)i+=String.fromCharCode(t[e>>5]>>>e%32&255);return i}function c(t){var e,i=[];for(i[(t.length>>2)-1]=void 0,e=0;e<i.length;e+=1)i[e]=0;for(e=0;e<8*t.length;e+=8)i[e>>5]|=(255&t.charCodeAt(e/8))<<e%32;return i}function p(t){return f(u(c(t),8*t.length))}function d(t,e){var i,n,r=c(t),o=[],s=[];for(o[15]=s[15]=void 0,r.length>16&&(r=u(r,8*t.length)),i=0;i<16;i+=1)o[i]=909522486^r[i],s[i]=1549556828^r[i];return n=u(o.concat(c(e)),512+8*e.length),f(u(s.concat(n),640))}function h(t){var e,i,n="";for(i=0;i<t.length;i+=1)e=t.charCodeAt(i),n+="0123456789abcdef".charAt(e>>>4&15)+"0123456789abcdef".charAt(15&e);return n}function l(t){return unescape(encodeURIComponent(t))}function g(t){return p(l(t))}function v(t){return h(g(t))}function m(t,e){return d(l(t),l(e))}function y(t,e){return h(m(t,e))}function w(t,e,i){return e?i?m(e,t):y(e,t):i?g(t):v(t)}"function"==typeof define&&define.amd?define(function(){return w}):t.md5=w}(this),function(){function t(t,e){var i=e||0,n=u;return n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+"-"+n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]+n[t[i++]]}function e(e,n,r){var o=n&&r||0;"string"==typeof e&&(n="binary"==e?new a(16):null,e=null);var s=(e=e||{}).random||(e.rng||i)();if(s[6]=15&s[6]|64,s[8]=63&s[8]|128,n)for(var u=0;u<16;u++)n[o+u]=s[u];return n||t(s)}var i,n=this;if("function"==typeof n.require)try{var r=n.require("crypto").randomBytes;i=r&&function(){return r(16)}}catch(t){}if(!i&&n.crypto&&crypto.getRandomValues){var o=new Uint8Array(16);i=function(){return crypto.getRandomValues(o),o}}if(!i){var s=new Array(16);i=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),s[e]=t>>>((3&e)<<3)&255;return s}}for(var a="function"==typeof n.Buffer?n.Buffer:Array,u=[],f={},c=0;c<256;c++)u[c]=(c+256).toString(16).substr(1),f[u[c]]=c;var p=i(),d=[1|p[0],p[1],p[2],p[3],p[4],p[5]],h=16383&(p[6]<<8|p[7]),l=0,g=0,v=e;if(v.v1=function(e,i,n){var r=i&&n||0,o=i||[],s=null!=(e=e||{}).clockseq?e.clockseq:h,a=null!=e.msecs?e.msecs:(new Date).getTime(),u=null!=e.nsecs?e.nsecs:g+1,f=a-l+(u-g)/1e4;if(f<0&&null==e.clockseq&&(s=s+1&16383),(f<0||a>l)&&null==e.nsecs&&(u=0),u>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");l=a,g=u,h=s;var c=(1e4*(268435455&(a+=122192928e5))+u)%4294967296;o[r++]=c>>>24&255,o[r++]=c>>>16&255,o[r++]=c>>>8&255,o[r++]=255&c;var p=a/4294967296*1e4&268435455;o[r++]=p>>>8&255,o[r++]=255&p,o[r++]=p>>>24&15|16,o[r++]=p>>>16&255,o[r++]=s>>>8|128,o[r++]=255&s;for(var v=e.node||d,m=0;m<6;m++)o[r+m]=v[m];return i||t(o)},v.v4=e,v.parse=function(t,e,i){var n=e&&i||0,r=0;for(e=e||[],t.toLowerCase().replace(/[0-9a-f]{2}/g,function(t){r<16&&(e[n+r++]=f[t])});r<16;)e[n+r++]=0;return e},v.unparse=t,v.BufferClass=a,"function"==typeof define&&define.amd)define(function(){return v});else if("undefined"!=typeof module&&module.exports)module.exports=v;else{var m=n.uuid;v.noConflict=function(){return n.uuid=m,v},n.uuid=v}}.call(this),function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function e(t){return a.raw?t:encodeURIComponent(t)}function i(t){return a.raw?t:decodeURIComponent(t)}function n(t){return e(a.json?JSON.stringify(t):String(t))}function r(t){0===t.indexOf('"')&&(t=t.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return t=decodeURIComponent(t.replace(s," ")),a.json?JSON.parse(t):t}catch(t){}}function o(e,i){var n=a.raw?e:r(e);return t.isFunction(i)?i(n):n}var s=/\+/g,a=t.cookie=function(r,s,u){if(void 0!==s&&!t.isFunction(s)){if("number"==typeof(u=t.extend({},a.defaults,u)).expires){var f=u.expires,c=u.expires=new Date;c.setTime(+c+864e5*f)}return document.cookie=[e(r),"=",n(s),u.expires?"; expires="+u.expires.toUTCString():"",u.path?"; path="+u.path:"",u.domain?"; domain="+u.domain:"",u.secure?"; secure":""].join("")}for(var p=r?void 0:{},d=document.cookie?document.cookie.split("; "):[],h=0,l=d.length;h<l;h++){var g=d[h].split("="),v=i(g.shift()),m=g.join("=");if(r&&r===v){p=o(m,s);break}r||void 0===(m=o(m))||(p[v]=m)}return p};a.defaults={},t.removeCookie=function(e,i){return void 0!==t.cookie(e)&&(t.cookie(e,"",t.extend({},i,{expires:-1})),!t.cookie(e))}}),function(t,e){if("function"==typeof define&&define.amd)define(["node-uuid","blueimp-md5","jquery","base-64","jquery.cookie"],e);else if("undefined"!=typeof exports){var i=require("node-uuid"),n=require("blueimp-md5"),r=require("jquery"),o=require("base-64");require("jquery.cookie");module.exports=e(i,n,r,o)}else t.TestTrack=e(t.uuid,t.md5,t.jQuery,t.base64)}(this,function(t,e,i,n){"use strict";if(void 0===t)throw new Error('TestTrack depends on node-uuid. Make sure you are including "node_modules/node-uuid/uuid.js"');if(void 0===e)throw new Error('TestTrack depends on blueimp-md5. Make sure you are including "node_modules/blueimp-md5/js/md5.js"');if(void 0===i)throw new Error('TestTrack depends on jquery. You can use your own copy of jquery or the one in "node_modules/jquery/dist/jquery.js"');if("function"!=typeof i.cookie)throw new Error("TestTrack depends on jquery.cookie. You can user your own copy of jquery.cooke or the one in node_modules/jquery.cookie/jquery.cookie.js");if(void 0===n)throw new Error('TestTrack depends on base-64. Make sure you are including "node_modules/base-64/base64.js"');Function.prototype.bind||(Function.prototype.bind=function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),i=this,n=function(){},r=function(){return i.apply(this instanceof n?this:t,e.concat(Array.prototype.slice.call(arguments)))};return this.prototype&&(n.prototype=this.prototype),r.prototype=new n,r});var r=function(){var t=function(){};return t.prototype.trackAssignment=function(t,e,i){var n={TTVisitorID:t,SplitName:e.getSplitName(),SplitVariant:e.getVariant(),SplitContext:e.getContext()};window.mixpanel&&window.mixpanel.track("SplitAssigned",n,i)},t.prototype.identify=function(t){window.mixpanel&&window.mixpanel.identify(t)},t.prototype.alias=function(t){window.mixpanel&&window.mixpanel.alias(t)},t}(),o=function(){var t=function(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("variant"))throw new Error("must provide variant");if(!t.hasOwnProperty("isUnsynced"))throw new Error("must provide isUnsynced");this._splitName=t.splitName,this._variant=t.variant,this._context=t.context,this._isUnsynced=t.isUnsynced};return t.fromJsonArray=function(t){for(var e=[],i=0;i<t.length;i++)e.push(new o({splitName:t[i].split_name,variant:t[i].variant,context:t[i].context,isUnsynced:t[i].unsynced}));return e},t.prototype.getSplitName=function(){return this._splitName},t.prototype.getVariant=function(){return this._variant},t.prototype.setVariant=function(t){this._variant=t},t.prototype.getContext=function(){return this._context},t.prototype.setContext=function(t){this._context=t},t.prototype.isUnsynced=function(){return this._isUnsynced},t.prototype.setUnsynced=function(t){this._isUnsynced=t},t}(),s=function(){var t=function(){};return t.prototype.getConfig=function(){return"function"==typeof window.atob?JSON.parse(window.atob(window.TT)):JSON.parse(n.decode(window.TT))},t}(),a=function(){var t,e,i=function(){if(!t){var e=new s;t=e.getConfig()}return t};return{_clear:function(){t=null},getUrl:function(){return i().url},getCookieDomain:function(){return i().cookieDomain},getCookieName:function(){return i().cookieName||"tt_visitor_id"},getSplitRegistry:function(){return i().registry},getAssignments:function(){var t=i().assignments;if(!t)return null;if(!e){e=[];for(var n in t)e.push(new o({splitName:n,variant:t[n],isUnsynced:!1}))}return e}}}(),u=function(){var t=function(t){if(this.visitor=t.visitor,this.splitName=t.splitName,!this.visitor)throw new Error("must provide visitor");if(!this.splitName)throw new Error("must provide splitName")};return t.prototype.getVariant=function(){if(!a.getSplitRegistry())return null;for(var t=0,e=this.getAssignmentBucket(),i=this.getWeighting(),n=this.getSortedVariants(),r=0;r<n.length;r++){var o=n[r];if((t+=i[o])>e)return o}throw new Error("Assignment bucket out of range. "+e+" unmatched in "+this.splitName+": "+JSON.stringify(i))},t.prototype.getSplitVisitorHash=function(){return e(this.splitName+this.visitor.getId())},t.prototype.getHashFixnum=function(){return parseInt(this.getSplitVisitorHash().substr(0,8),16)},t.prototype.getAssignmentBucket=function(){return this.getHashFixnum()%100},t.prototype.getSortedVariants=function(){return this.getVariants().sort()},t.prototype.getVariants=function(){return Object.getOwnPropertyNames(this.getWeighting())},t.prototype.getWeighting=function(){var t=a.getSplitRegistry()[this.splitName];if(!t){var e='Unknown split: "'+this.splitName+'"';throw this.visitor.logError(e),new Error(e)}return t},t}(),f=function(){var t=function(t){if(t=t||{},this._visitor=t.visitor,this._assignment=t.assignment,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment")};return t.prototype.send=function(){this.persistAssignment(),this._visitor.analytics.trackAssignment(this._visitor.getId(),this._assignment,function(t){this.persistAssignment(t?"success":"failure")}.bind(this))},t.prototype.persistAssignment=function(t){return i.ajax(a.getUrl()+"/api/v1/assignment_event",{method:"POST",dataType:"json",crossDomain:!0,data:{visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),context:this._assignment.getContext(),mixpanel_result:t}}).fail(function(t,e,i){var n=t&&t.status,r=t&&t.responseText;this._visitor.logError("test_track persistAssignment error: "+[t,n,r,e,i].join(", "))}.bind(this))},t}(),c=function(){var t=function(t){if(t=t||{},this._visitor=t.visitor,this._assignment=t.assignment,this._username=t.username,this._password=t.password,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment");if(!this._username)throw new Error("must provide username");if(!this._password)throw new Error("must provide password")};return t.prototype.send=function(){this.persistAssignment(),this._visitor.analytics.trackAssignment(this._visitor.getId(),this._assignment,function(t){this.persistAssignment(t?"success":"failure")}.bind(this))},t.prototype.persistAssignment=function(t){return i.ajax(a.getUrl()+"/api/v1/assignment_override",{method:"POST",dataType:"json",crossDomain:!0,headers:{Authorization:"Basic "+btoa(this._username+":"+this._password)},data:{visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),variant:this._assignment.getVariant(),context:this._assignment.getContext(),mixpanel_result:t}}).fail(function(t,e,i){var n=t&&t.status,r=t&&t.responseText;this._visitor.logError("test_track persistAssignment error: "+[t,n,r,e,i].join(", "))}.bind(this))},t}(),p=function(){var e=function(t){if(t=t||{},this._id=t.id,this._assignments=t.assignments,this._ttOffline=t.ttOffline,!this._id)throw new Error("must provide id");if(!this._assignments)throw new Error("must provide assignments");this._errorLogger=function(t){window.console.error(t)},this.analytics=new r};return e.loadVisitor=function(e){var n=i.Deferred(),r=function(t){n.resolve(new p(t))};return e?a.getAssignments()?r({id:e,assignments:a.getAssignments(),ttOffline:!1}):i.ajax(a.getUrl()+"/api/v1/visitors/"+e,{method:"GET",timeout:5e3}).done(function(t){r({id:t.id,assignments:o.fromJsonArray(t.assignments),ttOffline:!1})}).fail(function(){r({id:e,assignments:[],ttOffline:!0})}):r({id:t.v4(),assignments:[],ttOffline:!1}),n.promise()},e.prototype.getId=function(){return this._id},e.prototype.getAssignmentRegistry=function(){if(!this._assignmentRegistry){for(var t={},e=0;e<this._assignments.length;e++){var i=this._assignments[e];t[i.getSplitName()]=i}this._assignmentRegistry=t}return this._assignmentRegistry},e.prototype.vary=function(t,e){if("object"!=typeof e.variants)throw new Error("must provide variants object to `vary` for "+t);if(!e.context)throw new Error("must provide context to `vary` for "+t);if(!e.defaultVariant&&!1!==e.defaultVariant)throw new Error("must provide defaultVariant to `vary` for "+t);var i=e.defaultVariant.toString(),n=e.variants,r=e.context;if(!n.hasOwnProperty(i))throw new Error("defaultVariant: "+i+" must be represented in variants object");var o=this._getAssignmentFor(t,r),s=new l({assignment:o,visitor:this});for(var a in n)n.hasOwnProperty(a)&&(a===i?s.default(a,n[a]):s.when(a,n[a]));s.run(),s.isDefaulted()&&(o.setVariant(s.getDefaultVariant()),o.setUnsynced(!0),o.setContext(r)),this.notifyUnsyncedAssignments()},e.prototype.ab=function(t,e){var i=new g({splitName:t,trueVariant:e.trueVariant,visitor:this}).getVariants(),n={};n[i.true]=function(){e.callback(!0)},n[i.false]=function(){e.callback(!1)},this.vary(t,{context:e.context,variants:n,defaultVariant:i.false})},e.prototype.setErrorLogger=function(t){if("function"!=typeof t)throw new Error("must provide function for errorLogger");this._errorLogger=t},e.prototype.logError=function(t){this._errorLogger.call(null,t)},e.prototype.linkIdentifier=function(t,e){var n=i.Deferred();return new h({visitorId:this.getId(),identifierType:t,value:e}).save().then(function(t){this._merge(t),this.notifyUnsyncedAssignments(),n.resolve()}.bind(this)),n.promise()},e.prototype.setAnalytics=function(t){if("object"!=typeof t)throw new Error("must provide object for setAnalytics");this.analytics=t},e.prototype.notifyUnsyncedAssignments=function(){for(var t=this._getUnsyncedAssignments(),e=0;e<t.length;e++)this._notify(t[e])},e.prototype._getUnsyncedAssignments=function(){var t=[],e=this.getAssignmentRegistry();return Object.keys(e).forEach(function(i){var n=e[i];n.isUnsynced()&&t.push(n)}),t},e.prototype._merge=function(t){var e=this.getAssignmentRegistry(),i=t.getAssignmentRegistry();this._id=t.getId();for(var n in i)i.hasOwnProperty(n)&&(e[n]=i[n])},e.prototype._getAssignmentFor=function(t,e){return this.getAssignmentRegistry()[t]||this._generateAssignmentFor(t,e)},e.prototype._generateAssignmentFor=function(t,e){var i=new u({visitor:this,splitName:t}).getVariant();i||(this._ttOffline=!0);var n=new o({splitName:t,variant:i,context:e,isUnsynced:!0});return this._assignments.push(n),this._assignmentRegistry=null,n},e.prototype._notify=function(t){try{if(this._ttOffline)return;new f({visitor:this,assignment:t}).send(),t.setUnsynced(!1)}catch(t){this.logError("test_track notify error: "+t)}},e}(),d=function(){var t=function(){this._visitorDeferred=i.Deferred()};return t.prototype.initialize=function(t){var e=i.cookie(a.getCookieName());this._visitorDeferred.then(function(t){t.notifyUnsyncedAssignments()}),p.loadVisitor(e).then(function(e){t&&t.analytics&&e.setAnalytics(t.analytics),t&&t.errorLogger&&e.setErrorLogger(t.errorLogger),t&&"function"==typeof t.onVisitorLoaded&&t.onVisitorLoaded.call(null,e),this._visitorDeferred.resolve(e)}.bind(this)),this._setCookie()},t.prototype.vary=function(t,e){this._visitorDeferred.then(function(i){i.vary(t,e)})},t.prototype.ab=function(t,e){this._visitorDeferred.then(function(i){i.ab(t,e)})},t.prototype.logIn=function(t,e){var n=i.Deferred();return this._visitorDeferred.then(function(i){i.linkIdentifier(t,e).then(function(){this._setCookie(),i.analytics.identify(i.getId()),n.resolve()}.bind(this))}.bind(this)),n.promise()},t.prototype.signUp=function(t,e){var n=i.Deferred();return this._visitorDeferred.then(function(i){i.linkIdentifier(t,e).then(function(){this._setCookie(),i.analytics.alias(i.getId()),n.resolve()}.bind(this))}.bind(this)),n.promise()},t.prototype._setCookie=function(){this._visitorDeferred.then(function(t){i.cookie(a.getCookieName(),t.getId(),{expires:365,path:"/",domain:a.getCookieDomain()})})},t.prototype.getPublicAPI=function(){return{vary:this.vary.bind(this),ab:this.ab.bind(this),logIn:this.logIn.bind(this),signUp:this.signUp.bind(this),initialize:this.initialize.bind(this),_crx:{loadInfo:function(){var t=i.Deferred();return this._visitorDeferred.then(function(e){var i={};for(var n in e.getAssignmentRegistry())i[n]=e.getAssignmentRegistry()[n].getVariant();t.resolve({visitorId:e.getId(),splitRegistry:a.getSplitRegistry(),assignmentRegistry:i})}),t.promise()}.bind(this),persistAssignment:function(t,e,n,r){var s=i.Deferred();return this._visitorDeferred.then(function(i){new c({visitor:i,username:n,password:r,assignment:new o({splitName:t,variant:e,context:"chrome_extension",isUnsynced:!0})}).persistAssignment().then(function(){s.resolve()})}),s.promise()}.bind(this)}}},t}(),h=function(){var t=function(t){if(this.visitorId=t.visitorId,this.identifierType=t.identifierType,this.value=t.value,!this.visitorId)throw new Error("must provide visitorId");if(!this.identifierType)throw new Error("must provide identifierType");if(!this.value)throw new Error("must provide value")};return t.prototype.save=function(t,e){var n=i.Deferred();return i.ajax(a.getUrl()+"/api/v1/identifier",{method:"POST",dataType:"json",crossDomain:!0,data:{identifier_type:this.identifierType,value:this.value,visitor_id:this.visitorId}}).then(function(t){var e=new p({id:t.visitor.id,assignments:o.fromJsonArray(t.visitor.assignments)});n.resolve(e)}),n.promise()},t}(),l=function(){var t=function(t){if(!t.assignment)throw new Error("must provide assignment");if(!t.visitor)throw new Error("must provide visitor");this._assignment=t.assignment,this._visitor=t.visitor,this._splitRegistry=a.getSplitRegistry(),this._variantHandlers={}};return t.prototype.when=function(){var t=Array.prototype.slice.call(arguments,0),e=t.length-1,i="function"!=typeof t[0]&&t.length>0?t.slice(0,Math.max(1,e)):[],n=t[e];if(0===i.length)throw new Error("must provide at least one variant");for(var r=0;r<i.length;r++)this._assignHandlerToVariant(i[r],n)},t.prototype.default=function(t,e){if(this._defaultVariant)throw new Error("must provide exactly one `default`");this._defaultVariant=this._assignHandlerToVariant(t,e)},t.prototype.run=function(){this._validate();var t;this._variantHandlers[this._assignment.getVariant()]?t=this._variantHandlers[this._assignment.getVariant()]:(t=this._variantHandlers[this.getDefaultVariant()],this._defaulted=!0),t()},t.prototype.isDefaulted=function(){return this._defaulted||!1},t.prototype.getDefaultVariant=function(){return this._defaultVariant},t.prototype._assignHandlerToVariant=function(t,e){if("function"!=typeof e)throw new Error("must provide handler for "+t);return t=t.toString(),this._getSplit()&&!this._getSplit().hasOwnProperty(t)&&this._visitor.logError("configures unknown variant "+t),this._variantHandlers[t]=e,t},t.prototype._validate=function(){if(!this.getDefaultVariant())throw new Error("must provide exactly one `default`");if(this._getVariants().length<2)throw new Error("must provide at least one `when`");if(this._getSplit()){var t=this._getMissingVariants();if(t.length>0){var e=t.join(", ").replace(/, (.+)$/," and $1");this._visitor.logError("does not configure variants "+e)}}},t.prototype._getSplit=function(){return this._splitRegistry?this._splitRegistry[this._assignment.getSplitName()]:null},t.prototype._getVariants=function(){return Object.getOwnPropertyNames(this._variantHandlers)},t.prototype._getMissingVariants=function(){for(var t=this._getVariants(),e=this._getSplit(),i=Object.getOwnPropertyNames(e),n=[],r=0;r<i.length;r++){var o=i[r];-1===t.indexOf(o)&&n.push(o)}return n},t}(),g=function(){var t=function(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("trueVariant"))throw new Error("must provide trueVariant");if(!t.visitor)throw new Error("must provide visitor");this._splitName=t.splitName,this._trueVariant=t.trueVariant,this._visitor=t.visitor,this._splitRegistry=a.getSplitRegistry()};return t.prototype.getVariants=function(){var t=this._getSplitVariants();return t&&t.length>2&&this._visitor.logError("A/B for "+this._splitName+" configures split with more than 2 variants"),{true:this._getTrueVariant(),false:this._getFalseVariant()}},t.prototype._getTrueVariant=function(){return this._trueVariant||!0},t.prototype._getFalseVariant=function(){var t=this._getNonTrueVariants();return!!t&&t.sort()[0]},t.prototype._getNonTrueVariants=function(){var t=this._getSplitVariants();if(t){var e=this._getTrueVariant(),i=t.indexOf(e);return-1!==i&&t.splice(i,1),t}return null},t.prototype._getSplit=function(){return this._splitRegistry?this._splitRegistry[this._splitName]:null},t.prototype._getSplitVariants=function(){return this._getSplit()&&Object.getOwnPropertyNames(this._getSplit())},t}(),v=(new d).getPublicAPI(),m=function(){window.dispatchEvent(new CustomEvent("tt:lib:loaded",{detail:{TestTrack:v}}))};try{i(document).ready(function(){i(document.body).addClass("_tt");try{window.dispatchEvent(new CustomEvent("tt:class:added"))}catch(t){}}),m(),window.addEventListener("tt:listener:ready",m)}catch(t){}return v});
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).TestTrack=e()}(this,function(){"use strict";var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function e(t,e,r){return t(r={path:e,exports:{},require:function(t,e){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&r.path)}},r.exports),r.exports}var r=e(function(t,e){var r;r=function(){function t(){for(var t=0,e={};t<arguments.length;t++){var r=arguments[t];for(var n in r)e[n]=r[n]}return e}return function e(r){function n(e,i,o){var s;if("undefined"!=typeof document){if(arguments.length>1){if("number"==typeof(o=t({path:"/"},n.defaults,o)).expires){var a=new Date;a.setMilliseconds(a.getMilliseconds()+864e5*o.expires),o.expires=a}o.expires=o.expires?o.expires.toUTCString():"";try{s=JSON.stringify(i),/^[\{\[]/.test(s)&&(i=s)}catch(t){}i=r.write?r.write(i,e):encodeURIComponent(String(i)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),e=(e=(e=encodeURIComponent(String(e))).replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent)).replace(/[\(\)]/g,escape);var u="";for(var c in o)o[c]&&(u+="; "+c,!0!==o[c]&&(u+="="+o[c]));return document.cookie=e+"="+i+u}e||(s={});for(var f=document.cookie?document.cookie.split("; "):[],p=/(%[0-9A-Z]{2})+/g,l=0;l<f.length;l++){var d=f[l].split("="),h=d.slice(1).join("=");this.json||'"'!==h.charAt(0)||(h=h.slice(1,-1));try{var g=d[0].replace(p,decodeURIComponent);if(h=r.read?r.read(h,g):r(h,g)||h.replace(p,decodeURIComponent),this.json)try{h=JSON.parse(h)}catch(t){}if(e===g){s=h;break}e||(s[g]=h)}catch(t){}}return s}}return n.set=n,n.get=function(t){return n.call(n,t)},n.getJSON=function(){return n.apply({json:!0},[].slice.call(arguments))},n.defaults={},n.remove=function(e,r){n(e,"",t(r,{expires:-1}))},n.withConverter=e,n}(function(){})},t.exports=r()}),n=function(){function t(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("variant"))throw new Error("must provide variant");if(!t.hasOwnProperty("isUnsynced"))throw new Error("must provide isUnsynced");this._splitName=t.splitName,this._variant=t.variant,this._context=t.context,this._isUnsynced=t.isUnsynced}return t.fromJsonArray=function(e){return e.map(function(e){var r=e.split_name,n=e.variant;return new t({context:e.context,variant:n,splitName:r,isUnsynced:e.unsynced})})},t.prototype.getSplitName=function(){return this._splitName},t.prototype.getVariant=function(){return this._variant},t.prototype.setVariant=function(t){this._variant=t},t.prototype.getContext=function(){return this._context},t.prototype.setContext=function(t){this._context=t},t.prototype.isUnsynced=function(){return this._isUnsynced},t.prototype.setUnsynced=function(t){this._isUnsynced=t},t}(),i=Object.prototype.hasOwnProperty,o=Array.isArray,s=function(){for(var t=[],e=0;e<256;++e)t.push("%"+((e<16?"0":"")+e.toString(16)).toUpperCase());return t}(),a=function(t,e){for(var r=e&&e.plainObjects?Object.create(null):{},n=0;n<t.length;++n)void 0!==t[n]&&(r[n]=t[n]);return r},u={arrayToObject:a,assign:function(t,e){return Object.keys(e).reduce(function(t,r){return t[r]=e[r],t},t)},combine:function(t,e){return[].concat(t,e)},compact:function(t){for(var e=[{obj:{o:t},prop:"o"}],r=[],n=0;n<e.length;++n)for(var i=e[n],s=i.obj[i.prop],a=Object.keys(s),u=0;u<a.length;++u){var c=a[u],f=s[c];"object"==typeof f&&null!==f&&-1===r.indexOf(f)&&(e.push({obj:s,prop:c}),r.push(f))}return function(t){for(;t.length>1;){var e=t.pop(),r=e.obj[e.prop];if(o(r)){for(var n=[],i=0;i<r.length;++i)void 0!==r[i]&&n.push(r[i]);e.obj[e.prop]=n}}}(e),t},decode:function(t,e,r){var n=t.replace(/\+/g," ");if("iso-8859-1"===r)return n.replace(/%[0-9a-f]{2}/gi,unescape);try{return decodeURIComponent(n)}catch(t){return n}},encode:function(t,e,r){if(0===t.length)return t;var n=t;if("symbol"==typeof t?n=Symbol.prototype.toString.call(t):"string"!=typeof t&&(n=String(t)),"iso-8859-1"===r)return escape(n).replace(/%u[0-9a-f]{4}/gi,function(t){return"%26%23"+parseInt(t.slice(2),16)+"%3B"});for(var i="",o=0;o<n.length;++o){var a=n.charCodeAt(o);45===a||46===a||95===a||126===a||a>=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122?i+=n.charAt(o):a<128?i+=s[a]:a<2048?i+=s[192|a>>6]+s[128|63&a]:a<55296||a>=57344?i+=s[224|a>>12]+s[128|a>>6&63]+s[128|63&a]:(o+=1,a=65536+((1023&a)<<10|1023&n.charCodeAt(o)),i+=s[240|a>>18]+s[128|a>>12&63]+s[128|a>>6&63]+s[128|63&a])}return i},isBuffer:function(t){return!(!t||"object"!=typeof t||!(t.constructor&&t.constructor.isBuffer&&t.constructor.isBuffer(t)))},isRegExp:function(t){return"[object RegExp]"===Object.prototype.toString.call(t)},merge:function t(e,r,n){if(!r)return e;if("object"!=typeof r){if(o(e))e.push(r);else{if(!e||"object"!=typeof e)return[e,r];(n&&(n.plainObjects||n.allowPrototypes)||!i.call(Object.prototype,r))&&(e[r]=!0)}return e}if(!e||"object"!=typeof e)return[e].concat(r);var s=e;return o(e)&&!o(r)&&(s=a(e,n)),o(e)&&o(r)?(r.forEach(function(r,o){if(i.call(e,o)){var s=e[o];s&&"object"==typeof s&&r&&"object"==typeof r?e[o]=t(s,r,n):e.push(r)}else e[o]=r}),e):Object.keys(r).reduce(function(e,o){var s=r[o];return i.call(e,o)?e[o]=t(e[o],s,n):e[o]=s,e},s)}},c=String.prototype.replace,f=/%20/g,p={RFC1738:"RFC1738",RFC3986:"RFC3986"},l=u.assign({default:p.RFC3986,formatters:{RFC1738:function(t){return c.call(t,f,"+")},RFC3986:function(t){return String(t)}}},p),d=Object.prototype.hasOwnProperty,h={brackets:function(t){return t+"[]"},comma:"comma",indices:function(t,e){return t+"["+e+"]"},repeat:function(t){return t}},g=Array.isArray,m=Array.prototype.push,y=function(t,e){m.apply(t,g(e)?e:[e])},v=Date.prototype.toISOString,w=l.default,_={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:u.encode,encodeValuesOnly:!1,format:w,formatter:l.formatters[w],indices:!1,serializeDate:function(t){return v.call(t)},skipNulls:!1,strictNullHandling:!1},b=function t(e,r,n,i,o,s,a,c,f,p,l,d,h){var m,v=e;if("function"==typeof a?v=a(r,v):v instanceof Date?v=p(v):"comma"===n&&g(v)&&(v=v.join(",")),null===v){if(i)return s&&!d?s(r,_.encoder,h,"key"):r;v=""}if("string"==typeof(m=v)||"number"==typeof m||"boolean"==typeof m||"symbol"==typeof m||"bigint"==typeof m||u.isBuffer(v))return s?[l(d?r:s(r,_.encoder,h,"key"))+"="+l(s(v,_.encoder,h,"value"))]:[l(r)+"="+l(String(v))];var w,b=[];if(void 0===v)return b;if(g(a))w=a;else{var C=Object.keys(v);w=c?C.sort(c):C}for(var S=0;S<w.length;++S){var A=w[S];o&&null===v[A]||(g(v)?y(b,t(v[A],"function"==typeof n?n(r,A):r,n,i,o,s,a,c,f,p,l,d,h)):y(b,t(v[A],r+(f?"."+A:"["+A+"]"),n,i,o,s,a,c,f,p,l,d,h)))}return b},C=(Object.prototype.hasOwnProperty,Array.isArray,function(t,e){var r,n=t,i=function(t){if(!t)return _;if(null!==t.encoder&&void 0!==t.encoder&&"function"!=typeof t.encoder)throw new TypeError("Encoder has to be a function.");var e=t.charset||_.charset;if(void 0!==t.charset&&"utf-8"!==t.charset&&"iso-8859-1"!==t.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var r=l.default;if(void 0!==t.format){if(!d.call(l.formatters,t.format))throw new TypeError("Unknown format option provided.");r=t.format}var n=l.formatters[r],i=_.filter;return("function"==typeof t.filter||g(t.filter))&&(i=t.filter),{addQueryPrefix:"boolean"==typeof t.addQueryPrefix?t.addQueryPrefix:_.addQueryPrefix,allowDots:void 0===t.allowDots?_.allowDots:!!t.allowDots,charset:e,charsetSentinel:"boolean"==typeof t.charsetSentinel?t.charsetSentinel:_.charsetSentinel,delimiter:void 0===t.delimiter?_.delimiter:t.delimiter,encode:"boolean"==typeof t.encode?t.encode:_.encode,encoder:"function"==typeof t.encoder?t.encoder:_.encoder,encodeValuesOnly:"boolean"==typeof t.encodeValuesOnly?t.encodeValuesOnly:_.encodeValuesOnly,filter:i,formatter:n,serializeDate:"function"==typeof t.serializeDate?t.serializeDate:_.serializeDate,skipNulls:"boolean"==typeof t.skipNulls?t.skipNulls:_.skipNulls,sort:"function"==typeof t.sort?t.sort:null,strictNullHandling:"boolean"==typeof t.strictNullHandling?t.strictNullHandling:_.strictNullHandling}}(e);"function"==typeof i.filter?n=(0,i.filter)("",n):g(i.filter)&&(r=i.filter);var o,s=[];if("object"!=typeof n||null===n)return"";o=e&&e.arrayFormat in h?e.arrayFormat:e&&"indices"in e?e.indices?"indices":"repeat":"indices";var a=h[o];r||(r=Object.keys(n)),i.sort&&r.sort(i.sort);for(var u=0;u<r.length;++u){var c=r[u];i.skipNulls&&null===n[c]||y(s,b(n[c],c,a,i.strictNullHandling,i.skipNulls,i.encode?i.encoder:null,i.filter,i.sort,i.allowDots,i.serializeDate,i.formatter,i.encodeValuesOnly,i.charset))}var f=s.join(i.delimiter),p=!0===i.addQueryPrefix?"?":"";return i.charsetSentinel&&("iso-8859-1"===i.charset?p+="utf8=%26%2310003%3B&":p+="utf8=%E2%9C%93&"),f.length>0?p+f:""}),S=function(t,e){return function(){for(var r=new Array(arguments.length),n=0;n<r.length;n++)r[n]=arguments[n];return t.apply(e,r)}},A=Object.prototype.toString;function E(t){return"[object Array]"===A.call(t)}function x(t){return null!==t&&"object"==typeof t}function N(t){return"[object Function]"===A.call(t)}function j(t,e){if(null!=t)if("object"!=typeof t&&(t=[t]),E(t))for(var r=0,n=t.length;r<n;r++)e.call(null,t[r],r,t);else for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&e.call(null,t[i],i,t)}var R={isArray:E,isArrayBuffer:function(t){return"[object ArrayBuffer]"===A.call(t)},isBuffer:function(t){return null!=t&&null!=t.constructor&&"function"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)},isFormData:function(t){return"undefined"!=typeof FormData&&t instanceof FormData},isArrayBufferView:function(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer},isString:function(t){return"string"==typeof t},isNumber:function(t){return"number"==typeof t},isObject:x,isUndefined:function(t){return void 0===t},isDate:function(t){return"[object Date]"===A.call(t)},isFile:function(t){return"[object File]"===A.call(t)},isBlob:function(t){return"[object Blob]"===A.call(t)},isFunction:N,isStream:function(t){return x(t)&&N(t.pipe)},isURLSearchParams:function(t){return"undefined"!=typeof URLSearchParams&&t instanceof URLSearchParams},isStandardBrowserEnv:function(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&"undefined"!=typeof window&&"undefined"!=typeof document},forEach:j,merge:function t(){var e={};function r(r,n){"object"==typeof e[n]&&"object"==typeof r?e[n]=t(e[n],r):e[n]=r}for(var n=0,i=arguments.length;n<i;n++)j(arguments[n],r);return e},deepMerge:function t(){var e={};function r(r,n){"object"==typeof e[n]&&"object"==typeof r?e[n]=t(e[n],r):e[n]="object"==typeof r?t({},r):r}for(var n=0,i=arguments.length;n<i;n++)j(arguments[n],r);return e},extend:function(t,e,r){return j(e,function(e,n){t[n]=r&&"function"==typeof e?S(e,r):e}),t},trim:function(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}};function V(t){return encodeURIComponent(t).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var O=function(t,e,r){if(!e)return t;var n;if(r)n=r(e);else if(R.isURLSearchParams(e))n=e.toString();else{var i=[];R.forEach(e,function(t,e){null!=t&&(R.isArray(t)?e+="[]":t=[t],R.forEach(t,function(t){R.isDate(t)?t=t.toISOString():R.isObject(t)&&(t=JSON.stringify(t)),i.push(V(e)+"="+V(t))}))}),n=i.join("&")}if(n){var o=t.indexOf("#");-1!==o&&(t=t.slice(0,o)),t+=(-1===t.indexOf("?")?"?":"&")+n}return t};function k(){this.handlers=[]}k.prototype.use=function(t,e){return this.handlers.push({fulfilled:t,rejected:e}),this.handlers.length-1},k.prototype.eject=function(t){this.handlers[t]&&(this.handlers[t]=null)},k.prototype.forEach=function(t){R.forEach(this.handlers,function(e){null!==e&&t(e)})};var U=k,T=function(t,e,r){return R.forEach(r,function(r){t=r(t,e)}),t},D=function(t){return!(!t||!t.__CANCEL__)},L=function(t,e){R.forEach(t,function(r,n){n!==e&&n.toUpperCase()===e.toUpperCase()&&(t[e]=r,delete t[n])})},I=function(t,e,r,n,i){return function(t,e,r,n,i){return t.config=e,r&&(t.code=r),t.request=n,t.response=i,t.isAxiosError=!0,t.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},t}(new Error(t),e,r,n,i)},P=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"],B=R.isStandardBrowserEnv()?function(){var t,e=/(msie|trident)/i.test(navigator.userAgent),r=document.createElement("a");function n(t){var n=t;return e&&(r.setAttribute("href",n),n=r.href),r.setAttribute("href",n),{href:r.href,protocol:r.protocol?r.protocol.replace(/:$/,""):"",host:r.host,search:r.search?r.search.replace(/^\?/,""):"",hash:r.hash?r.hash.replace(/^#/,""):"",hostname:r.hostname,port:r.port,pathname:"/"===r.pathname.charAt(0)?r.pathname:"/"+r.pathname}}return t=n(window.location.href),function(e){var r=R.isString(e)?n(e):e;return r.protocol===t.protocol&&r.host===t.host}}():function(){return!0},F=R.isStandardBrowserEnv()?{write:function(t,e,r,n,i,o){var s=[];s.push(t+"="+encodeURIComponent(e)),R.isNumber(r)&&s.push("expires="+new Date(r).toGMTString()),R.isString(n)&&s.push("path="+n),R.isString(i)&&s.push("domain="+i),!0===o&&s.push("secure"),document.cookie=s.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}},H=function(t){return new Promise(function(e,r){var n=t.data,i=t.headers;R.isFormData(n)&&delete i["Content-Type"];var o=new XMLHttpRequest;if(t.auth){var s=t.auth.username||"",a=t.auth.password||"";i.Authorization="Basic "+btoa(s+":"+a)}if(o.open(t.method.toUpperCase(),O(t.url,t.params,t.paramsSerializer),!0),o.timeout=t.timeout,o.onreadystatechange=function(){if(o&&4===o.readyState&&(0!==o.status||o.responseURL&&0===o.responseURL.indexOf("file:"))){var n,i,s,a,u,c="getAllResponseHeaders"in o?(n=o.getAllResponseHeaders(),u={},n?(R.forEach(n.split("\n"),function(t){if(a=t.indexOf(":"),i=R.trim(t.substr(0,a)).toLowerCase(),s=R.trim(t.substr(a+1)),i){if(u[i]&&P.indexOf(i)>=0)return;u[i]="set-cookie"===i?(u[i]?u[i]:[]).concat([s]):u[i]?u[i]+", "+s:s}}),u):u):null,f={data:t.responseType&&"text"!==t.responseType?o.response:o.responseText,status:o.status,statusText:o.statusText,headers:c,config:t,request:o};!function(t,e,r){var n=r.config.validateStatus;!n||n(r.status)?t(r):e(I("Request failed with status code "+r.status,r.config,null,r.request,r))}(e,r,f),o=null}},o.onabort=function(){o&&(r(I("Request aborted",t,"ECONNABORTED",o)),o=null)},o.onerror=function(){r(I("Network Error",t,null,o)),o=null},o.ontimeout=function(){r(I("timeout of "+t.timeout+"ms exceeded",t,"ECONNABORTED",o)),o=null},R.isStandardBrowserEnv()){var u=F,c=(t.withCredentials||B(t.url))&&t.xsrfCookieName?u.read(t.xsrfCookieName):void 0;c&&(i[t.xsrfHeaderName]=c)}if("setRequestHeader"in o&&R.forEach(i,function(t,e){void 0===n&&"content-type"===e.toLowerCase()?delete i[e]:o.setRequestHeader(e,t)}),t.withCredentials&&(o.withCredentials=!0),t.responseType)try{o.responseType=t.responseType}catch(e){if("json"!==t.responseType)throw e}"function"==typeof t.onDownloadProgress&&o.addEventListener("progress",t.onDownloadProgress),"function"==typeof t.onUploadProgress&&o.upload&&o.upload.addEventListener("progress",t.onUploadProgress),t.cancelToken&&t.cancelToken.promise.then(function(t){o&&(o.abort(),r(t),o=null)}),void 0===n&&(n=null),o.send(n)})},q={"Content-Type":"application/x-www-form-urlencoded"};function z(t,e){!R.isUndefined(t)&&R.isUndefined(t["Content-Type"])&&(t["Content-Type"]=e)}var J,M={adapter:("undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?J=H:"undefined"!=typeof XMLHttpRequest&&(J=H),J),transformRequest:[function(t,e){return L(e,"Accept"),L(e,"Content-Type"),R.isFormData(t)||R.isArrayBuffer(t)||R.isBuffer(t)||R.isStream(t)||R.isFile(t)||R.isBlob(t)?t:R.isArrayBufferView(t)?t.buffer:R.isURLSearchParams(t)?(z(e,"application/x-www-form-urlencoded;charset=utf-8"),t.toString()):R.isObject(t)?(z(e,"application/json;charset=utf-8"),JSON.stringify(t)):t}],transformResponse:[function(t){if("string"==typeof t)try{t=JSON.parse(t)}catch(t){}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(t){return t>=200&&t<300}};M.headers={common:{Accept:"application/json, text/plain, */*"}},R.forEach(["delete","get","head"],function(t){M.headers[t]={}}),R.forEach(["post","put","patch"],function(t){M.headers[t]=R.merge(q)});var $=M;function W(t){t.cancelToken&&t.cancelToken.throwIfRequested()}var Q=function(t){var e,r,n;return W(t),t.baseURL&&(n=t.url,!/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(n))&&(t.url=(e=t.baseURL,(r=t.url)?e.replace(/\/+$/,"")+"/"+r.replace(/^\/+/,""):e)),t.headers=t.headers||{},t.data=T(t.data,t.headers,t.transformRequest),t.headers=R.merge(t.headers.common||{},t.headers[t.method]||{},t.headers||{}),R.forEach(["delete","get","head","post","put","patch","common"],function(e){delete t.headers[e]}),(t.adapter||$.adapter)(t).then(function(e){return W(t),e.data=T(e.data,e.headers,t.transformResponse),e},function(e){return D(e)||(W(t),e&&e.response&&(e.response.data=T(e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)})},X=function(t,e){e=e||{};var r={};return R.forEach(["url","method","params","data"],function(t){void 0!==e[t]&&(r[t]=e[t])}),R.forEach(["headers","auth","proxy"],function(n){R.isObject(e[n])?r[n]=R.deepMerge(t[n],e[n]):void 0!==e[n]?r[n]=e[n]:R.isObject(t[n])?r[n]=R.deepMerge(t[n]):void 0!==t[n]&&(r[n]=t[n])}),R.forEach(["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","maxContentLength","validateStatus","maxRedirects","httpAgent","httpsAgent","cancelToken","socketPath"],function(n){void 0!==e[n]?r[n]=e[n]:void 0!==t[n]&&(r[n]=t[n])}),r};function G(t){this.defaults=t,this.interceptors={request:new U,response:new U}}G.prototype.request=function(t){"string"==typeof t?(t=arguments[1]||{}).url=arguments[0]:t=t||{},(t=X(this.defaults,t)).method=t.method?t.method.toLowerCase():"get";var e=[Q,void 0],r=Promise.resolve(t);for(this.interceptors.request.forEach(function(t){e.unshift(t.fulfilled,t.rejected)}),this.interceptors.response.forEach(function(t){e.push(t.fulfilled,t.rejected)});e.length;)r=r.then(e.shift(),e.shift());return r},G.prototype.getUri=function(t){return t=X(this.defaults,t),O(t.url,t.params,t.paramsSerializer).replace(/^\?/,"")},R.forEach(["delete","get","head","options"],function(t){G.prototype[t]=function(e,r){return this.request(R.merge(r||{},{method:t,url:e}))}}),R.forEach(["post","put","patch"],function(t){G.prototype[t]=function(e,r,n){return this.request(R.merge(n||{},{method:t,url:e,data:r}))}});var Z=G;function K(t){this.message=t}K.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},K.prototype.__CANCEL__=!0;var Y=K;function tt(t){if("function"!=typeof t)throw new TypeError("executor must be a function.");var e;this.promise=new Promise(function(t){e=t});var r=this;t(function(t){r.reason||(r.reason=new Y(t),e(r.reason))})}tt.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},tt.source=function(){var t;return{token:new tt(function(e){t=e}),cancel:t}};var et=tt;function rt(t){var e=new Z(t),r=S(Z.prototype.request,e);return R.extend(r,Z.prototype,e),R.extend(r,e),r}var nt=rt($);nt.Axios=Z,nt.create=function(t){return rt(X(nt.defaults,t))},nt.Cancel=Y,nt.CancelToken=et,nt.isCancel=D,nt.all=function(t){return Promise.all(t)},nt.spread=function(t){return function(e){return t.apply(null,e)}};var it=nt,ot=nt;it.default=ot;var st=it;for(var at={atob:function(t){if((t=(t=`${t}`).replace(/[ \t\n\f\r]/g,"")).length%4==0&&(t=t.replace(/==?$/,"")),t.length%4==1||/[^+\/0-9A-Za-z]/.test(t))return null;let e="",r=0,n=0;for(let o=0;o<t.length;o++)r<<=6,r|=(i=t[o],/[A-Z]/.test(i)?i.charCodeAt(0)-"A".charCodeAt(0):/[a-z]/.test(i)?i.charCodeAt(0)-"a".charCodeAt(0)+26:/[0-9]/.test(i)?i.charCodeAt(0)-"0".charCodeAt(0)+52:"+"===i?62:"/"===i?63:void 0),24===(n+=6)&&(e+=String.fromCharCode((16711680&r)>>16),e+=String.fromCharCode((65280&r)>>8),e+=String.fromCharCode(255&r),r=n=0);var i;return 12===n?(r>>=4,e+=String.fromCharCode(r)):18===n&&(r>>=2,e+=String.fromCharCode((65280&r)>>8),e+=String.fromCharCode(255&r)),e},btoa:function(t){let e;for(t=`${t}`,e=0;e<t.length;e++)if(t.charCodeAt(e)>255)return null;let r="";for(e=0;e<t.length;e+=3){const i=[void 0,void 0,void 0,void 0];i[0]=t.charCodeAt(e)>>2,i[1]=(3&t.charCodeAt(e))<<4,t.length>e+1&&(i[1]|=t.charCodeAt(e+1)>>4,i[2]=(15&t.charCodeAt(e+1))<<2),t.length>e+2&&(i[2]|=t.charCodeAt(e+2)>>6,i[3]=63&t.charCodeAt(e+2));for(let t=0;t<i.length;t++)void 0===i[t]?r+="=":r+=(n=i[t])<26?String.fromCharCode(n+"A".charCodeAt(0)):n<52?String.fromCharCode(n-26+"a".charCodeAt(0)):n<62?String.fromCharCode(n-52+"0".charCodeAt(0)):62===n?"+":63===n?"/":void 0}var n;return r}},ut=function(){function t(){}return t.prototype.getConfig=function(){var t=at.atob(window.TT);if(t)return JSON.parse(t);throw new Error("Unable to parse configuration")},t}(),ct=function(){function t(t,e,r){this._name=t,this._isFeatureGate=e,this._weighting=r}return t.prototype.getName=function(){return this._name},t.prototype.isFeatureGate=function(){return this._isFeatureGate},t.prototype.getVariants=function(){return Object.keys(this._weighting)},t.prototype.getWeighting=function(){return this._weighting},t.prototype.hasVariant=function(t){return t in this._weighting},t}(),ft=function(){return(ft=Object.assign||function(t){for(var e,r=1,n=arguments.length;r<n;r++)for(var i in e=arguments[r])Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t}).apply(this,arguments)},pt=function(){function t(t){this._splitArray=t||[],this._loaded=null!==t}return t.prototype.getSplit=function(t){return this.getSplits()[t]},t.prototype.isLoaded=function(){return this._loaded},t.prototype.asV1Hash=function(){var t={};for(var e in this.getSplits()){var r=this.getSplits()[e];t[e]=r.getWeighting()}return t},t.prototype.getSplits=function(){return this._loaded?(this._splits||(this._splits=this._splitArray.reduce(function(t,e){var r;return ft(ft({},t),((r={})[e.getName()]=e,r))},{})),this._splits):{}},t}(),lt=null,dt=null,ht=null,gt=function(){if(!lt){var t=new ut;lt=t.getConfig()}return lt},mt={_clear:function(){lt=null},getUrl:function(){return gt().url},getCookieDomain:function(){return gt().cookieDomain},getCookieName:function(){return gt().cookieName||"tt_visitor_id"},getExperienceSamplingWeight:function(){return gt().experienceSamplingWeight},getSplitRegistry:function(){var t=gt().splits;if(!t)return new pt(null);if(!ht){var e=Object.keys(t).map(function(e){var r=t[e];return new ct(e,r.feature_gate,r.weights)});ht=new pt(e)}return ht},getAssignments:function(){var t=gt().assignments;if(!t)return null;if(!dt)for(var e in dt=[],t)dt.push(new n({splitName:e,variant:t[e],isUnsynced:!1}));return dt}},yt=st.create({baseURL:mt.getUrl()+"/api",headers:{"Content-Type":"application/x-www-form-urlencoded"},crossDomain:!0}),vt=function(){function t(t){if(this._visitor=t.visitor,this._assignment=t.assignment,this._username=t.username,this._password=t.password,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment");if(!this._username)throw new Error("must provide username");if(!this._password)throw new Error("must provide password")}return t.prototype.persistAssignment=function(){var t=this;return yt.post("/v1/assignment_override",C({visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),variant:this._assignment.getVariant(),context:this._assignment.getContext(),mixpanel_result:"success"}),{auth:{username:this._username,password:this._password}}).catch(function(e){if(e.response){var r=e.response,n=r.status,i=r.statusText,o=r.data;t._visitor.logError("test_track persistAssignment response error: "+n+", "+i+", "+o)}else t._visitor.logError("test_track persistAssignment other error: "+e)})},t}(),wt=function(){function t(t){if(!t.splitName)throw new Error("must provide splitName");if(!t.hasOwnProperty("trueVariant"))throw new Error("must provide trueVariant");if(!t.visitor)throw new Error("must provide visitor");this._splitName=t.splitName,this._trueVariant=t.trueVariant,this._visitor=t.visitor,this._splitRegistry=mt.getSplitRegistry()}return t.prototype.getVariants=function(){var t=this._getSplitVariants();return t&&t.length>2&&this._visitor.logError("A/B for "+this._splitName+" configures split with more than 2 variants"),{true:this._getTrueVariant(),false:this._getFalseVariant()}},t.prototype._getTrueVariant=function(){return this._trueVariant||"true"},t.prototype._getFalseVariant=function(){var t=this._getNonTrueVariants();return Array.isArray(t)&&0!==t.length?t.sort()[0]:"false"},t.prototype._getNonTrueVariants=function(){var t=this._getSplitVariants();if(t){var e=this._getTrueVariant(),r=t.indexOf(e.toString());return-1!==r&&t.splice(r,1),t}return null},t.prototype._getSplit=function(){return this._splitRegistry.getSplit(this._splitName)},t.prototype._getSplitVariants=function(){return this._getSplit()&&this._getSplit().getVariants()},t}(),_t=function(){function t(t){var e=t.visitor,r=t.assignment;if(this._visitor=e,this._assignment=r,!this._visitor)throw new Error("must provide visitor");if(!this._assignment)throw new Error("must provide assignment")}return t.prototype.send=function(){var t=this,e=this._persistAssignment(),r=new Promise(function(e){t._visitor.analytics.trackAssignment(t._visitor.getId(),t._assignment,function(r){return t._persistAssignment(r?"success":"failure").then(e)})});return Promise.all([e,r])},t.prototype._persistAssignment=function(t){var e=this;return yt.post("/v1/assignment_event",C({visitor_id:this._visitor.getId(),split_name:this._assignment.getSplitName(),context:this._assignment.getContext(),mixpanel_result:t})).catch(function(t){if(t.response){var r=t.response,n=r.status,i=r.statusText,o=r.data;e._visitor.logError("test_track persistAssignment response error: "+n+", "+i+", "+o)}else e._visitor.logError("test_track persistAssignment other error: "+t)})},t}(),bt=function(){function t(t){if(this.visitorId=t.visitorId,this.identifierType=t.identifierType,this.value=t.value,!this.visitorId)throw new Error("must provide visitorId");if(!this.identifierType)throw new Error("must provide identifierType");if(!this.value)throw new Error("must provide value")}return t.prototype.save=function(){return yt.post("/v1/identifier",C({identifier_type:this.identifierType,value:this.value,visitor_id:this.visitorId})).then(function(t){var e=t.data;return new Ot({id:e.visitor.id,assignments:n.fromJsonArray(e.visitor.assignments)})})},t}(),Ct=function(){function t(){}return t.prototype.trackAssignment=function(t,e,r){var n={TTVisitorID:t,SplitName:e.getSplitName(),SplitVariant:e.getVariant(),SplitContext:e.getContext()};window.mixpanel&&window.mixpanel.track("SplitAssigned",n,r)},t.prototype.identify=function(t){window.mixpanel&&window.mixpanel.identify(t)},t.prototype.alias=function(t){window.mixpanel&&window.mixpanel.alias(t)},t}(),St=e(function(t){var e="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof window.msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto);if(e){var r=new Uint8Array(16);t.exports=function(){return e(r),r}}else{var n=new Array(16);t.exports=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),n[e]=t>>>((3&e)<<3)&255;return n}}}),At=[],Et=0;Et<256;++Et)At[Et]=(Et+256).toString(16).substr(1);var xt=function(t,e){var r=e||0,n=At;return[n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],"-",n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]],n[t[r++]]].join("")};var Nt=function(t,e,r){var n=e&&r||0;"string"==typeof t&&(e="binary"===t?new Array(16):null,t=null);var i=(t=t||{}).random||(t.rng||St)();if(i[6]=15&i[6]|64,i[8]=63&i[8]|128,e)for(var o=0;o<16;++o)e[n+o]=i[o];return e||xt(i)},jt=e(function(e){!function(t){function r(t,e){var r=(65535&t)+(65535&e);return(t>>16)+(e>>16)+(r>>16)<<16|65535&r}function n(t,e,n,i,o,s){return r((a=r(r(e,t),r(i,s)))<<(u=o)|a>>>32-u,n);var a,u}function i(t,e,r,i,o,s,a){return n(e&r|~e&i,t,e,o,s,a)}function o(t,e,r,i,o,s,a){return n(e&i|r&~i,t,e,o,s,a)}function s(t,e,r,i,o,s,a){return n(e^r^i,t,e,o,s,a)}function a(t,e,r,i,o,s,a){return n(r^(e|~i),t,e,o,s,a)}function u(t,e){var n,u,c,f,p;t[e>>5]|=128<<e%32,t[14+(e+64>>>9<<4)]=e;var l=1732584193,d=-271733879,h=-1732584194,g=271733878;for(n=0;n<t.length;n+=16)u=l,c=d,f=h,p=g,l=i(l,d,h,g,t[n],7,-680876936),g=i(g,l,d,h,t[n+1],12,-389564586),h=i(h,g,l,d,t[n+2],17,606105819),d=i(d,h,g,l,t[n+3],22,-1044525330),l=i(l,d,h,g,t[n+4],7,-176418897),g=i(g,l,d,h,t[n+5],12,1200080426),h=i(h,g,l,d,t[n+6],17,-1473231341),d=i(d,h,g,l,t[n+7],22,-45705983),l=i(l,d,h,g,t[n+8],7,1770035416),g=i(g,l,d,h,t[n+9],12,-1958414417),h=i(h,g,l,d,t[n+10],17,-42063),d=i(d,h,g,l,t[n+11],22,-1990404162),l=i(l,d,h,g,t[n+12],7,1804603682),g=i(g,l,d,h,t[n+13],12,-40341101),h=i(h,g,l,d,t[n+14],17,-1502002290),l=o(l,d=i(d,h,g,l,t[n+15],22,1236535329),h,g,t[n+1],5,-165796510),g=o(g,l,d,h,t[n+6],9,-1069501632),h=o(h,g,l,d,t[n+11],14,643717713),d=o(d,h,g,l,t[n],20,-373897302),l=o(l,d,h,g,t[n+5],5,-701558691),g=o(g,l,d,h,t[n+10],9,38016083),h=o(h,g,l,d,t[n+15],14,-660478335),d=o(d,h,g,l,t[n+4],20,-405537848),l=o(l,d,h,g,t[n+9],5,568446438),g=o(g,l,d,h,t[n+14],9,-1019803690),h=o(h,g,l,d,t[n+3],14,-187363961),d=o(d,h,g,l,t[n+8],20,1163531501),l=o(l,d,h,g,t[n+13],5,-1444681467),g=o(g,l,d,h,t[n+2],9,-51403784),h=o(h,g,l,d,t[n+7],14,1735328473),l=s(l,d=o(d,h,g,l,t[n+12],20,-1926607734),h,g,t[n+5],4,-378558),g=s(g,l,d,h,t[n+8],11,-2022574463),h=s(h,g,l,d,t[n+11],16,1839030562),d=s(d,h,g,l,t[n+14],23,-35309556),l=s(l,d,h,g,t[n+1],4,-1530992060),g=s(g,l,d,h,t[n+4],11,1272893353),h=s(h,g,l,d,t[n+7],16,-155497632),d=s(d,h,g,l,t[n+10],23,-1094730640),l=s(l,d,h,g,t[n+13],4,681279174),g=s(g,l,d,h,t[n],11,-358537222),h=s(h,g,l,d,t[n+3],16,-722521979),d=s(d,h,g,l,t[n+6],23,76029189),l=s(l,d,h,g,t[n+9],4,-640364487),g=s(g,l,d,h,t[n+12],11,-421815835),h=s(h,g,l,d,t[n+15],16,530742520),l=a(l,d=s(d,h,g,l,t[n+2],23,-995338651),h,g,t[n],6,-198630844),g=a(g,l,d,h,t[n+7],10,1126891415),h=a(h,g,l,d,t[n+14],15,-1416354905),d=a(d,h,g,l,t[n+5],21,-57434055),l=a(l,d,h,g,t[n+12],6,1700485571),g=a(g,l,d,h,t[n+3],10,-1894986606),h=a(h,g,l,d,t[n+10],15,-1051523),d=a(d,h,g,l,t[n+1],21,-2054922799),l=a(l,d,h,g,t[n+8],6,1873313359),g=a(g,l,d,h,t[n+15],10,-30611744),h=a(h,g,l,d,t[n+6],15,-1560198380),d=a(d,h,g,l,t[n+13],21,1309151649),l=a(l,d,h,g,t[n+4],6,-145523070),g=a(g,l,d,h,t[n+11],10,-1120210379),h=a(h,g,l,d,t[n+2],15,718787259),d=a(d,h,g,l,t[n+9],21,-343485551),l=r(l,u),d=r(d,c),h=r(h,f),g=r(g,p);return[l,d,h,g]}function c(t){var e,r="",n=32*t.length;for(e=0;e<n;e+=8)r+=String.fromCharCode(t[e>>5]>>>e%32&255);return r}function f(t){var e,r=[];for(r[(t.length>>2)-1]=void 0,e=0;e<r.length;e+=1)r[e]=0;var n=8*t.length;for(e=0;e<n;e+=8)r[e>>5]|=(255&t.charCodeAt(e/8))<<e%32;return r}function p(t){var e,r,n="";for(r=0;r<t.length;r+=1)e=t.charCodeAt(r),n+="0123456789abcdef".charAt(e>>>4&15)+"0123456789abcdef".charAt(15&e);return n}function l(t){return unescape(encodeURIComponent(t))}function d(t){return function(t){return c(u(f(t),8*t.length))}(l(t))}function h(t,e){return function(t,e){var r,n,i=f(t),o=[],s=[];for(o[15]=s[15]=void 0,i.length>16&&(i=u(i,8*t.length)),r=0;r<16;r+=1)o[r]=909522486^i[r],s[r]=1549556828^i[r];return n=u(o.concat(f(e)),512+8*e.length),c(u(s.concat(n),640))}(l(t),l(e))}function g(t,e,r){return e?r?h(e,t):p(h(e,t)):r?d(t):p(d(t))}e.exports?e.exports=g:t.md5=g}(t)}),Rt=function(){function t(t){if(this.visitor=t.visitor,this.splitName=t.splitName,!this.visitor)throw new Error("must provide visitor");if(!this.splitName)throw new Error("must provide splitName")}return t.prototype.getVariant=function(){if(!mt.getSplitRegistry().isLoaded())return null;for(var t=0,e=this.getAssignmentBucket(),r=this.getWeighting(),n=this.getSortedVariants(),i=0;i<n.length;i++){var o=n[i];if((t+=r[o])>e)return o}throw new Error("Assignment bucket out of range. "+e+" unmatched in "+this.splitName+": "+JSON.stringify(r))},t.prototype.getSplitVisitorHash=function(){return jt(this.splitName+this.visitor.getId())},t.prototype.getHashFixnum=function(){return parseInt(this.getSplitVisitorHash().substr(0,8),16)},t.prototype.getAssignmentBucket=function(){return this.getHashFixnum()%100},t.prototype.getSortedVariants=function(){return this.getVariants().sort()},t.prototype.getVariants=function(){return Object.getOwnPropertyNames(this.getWeighting())},t.prototype.getWeighting=function(){var t=mt.getSplitRegistry().getSplit(this.splitName);if(!t){var e='Unknown split: "'+this.splitName+'"';throw this.visitor.logError(e),new Error(e)}return t.getWeighting()},t}(),Vt=function(){function t(t){if(!t.assignment)throw new Error("must provide assignment");if(!t.visitor)throw new Error("must provide visitor");this._assignment=t.assignment,this._visitor=t.visitor,this._splitRegistry=mt.getSplitRegistry(),this._variantHandlers={}}return t.prototype.when=function(){for(var t=this,e=[],r=0;r<arguments.length;r++)e[r]=arguments[r];var n="function"==typeof e[e.length-1]?e.pop():null;if(0===e.length)throw new Error("must provide at least one variant");e.forEach(function(e){"string"==typeof e&&t._assignHandlerToVariant(e,n)})},t.prototype.default=function(t,e){if(this._defaultVariant)throw new Error("must provide exactly one `default`");this._defaultVariant=this._assignHandlerToVariant(t,e)},t.prototype.run=function(){this._validate();var t=this.getDefaultVariant();if(void 0===t)throw new Error("must provide exactly one `default`");var e=this._variantHandlers[t],r=this._assignment.getVariant();r&&this._variantHandlers[r]?e=this._variantHandlers[r]:this._defaulted=!0,e()},t.prototype.isDefaulted=function(){return this._defaulted||!1},t.prototype.getDefaultVariant=function(){return this._defaultVariant},t.prototype._assignHandlerToVariant=function(t,e){if("function"!=typeof e)throw new Error("must provide handler for "+t);return t=t.toString(),this._getSplit()&&!this._getSplit().hasVariant(t)&&this._visitor.logError("configures unknown variant "+t),this._variantHandlers[t]=e,t},t.prototype._validate=function(){if(!this.getDefaultVariant())throw new Error("must provide exactly one `default`");if(this._getVariants().length<2)throw new Error("must provide at least one `when`");if(this._getSplit()){var t=this._getMissingVariants();if(t.length>0){var e=t.join(", ").replace(/, (.+)$/," and $1");this._visitor.logError("does not configure variants "+e)}}},t.prototype._getSplit=function(){return this._splitRegistry.getSplit(this._assignment.getSplitName())},t.prototype._getVariants=function(){return Object.getOwnPropertyNames(this._variantHandlers)},t.prototype._getMissingVariants=function(){var t=this._getVariants();return this._getSplit().getVariants().filter(function(e){return!t.includes(e)})},t}(),Ot=function(){function t(t){var e=t.id,r=t.assignments,n=t.ttOffline;if(this._id=e,this._assignments=r,this._ttOffline=n,!this._id)throw new Error("must provide id");if(!this._assignments)throw new Error("must provide assignments");this._errorLogger=function(t){window.console.error(t)},this.analytics=new Ct}return t.loadVisitor=function(e){if(e){var r=mt.getAssignments();return r?Promise.resolve(new t({id:e,assignments:r,ttOffline:!1})):yt.get("/v1/visitors/"+e,{timeout:5e3}).then(function(e){var r=e.data;return new t({id:r.id,assignments:n.fromJsonArray(r.assignments),ttOffline:!1})}).catch(function(){return new t({id:e,assignments:[],ttOffline:!0})})}return Promise.resolve(new t({id:Nt(),assignments:[],ttOffline:!1}))},t.prototype.getId=function(){return this._id},t.prototype.getAssignmentRegistry=function(){return this._assignmentRegistry||(this._assignmentRegistry=this._assignments.reduce(function(t,e){var r;return ft(ft({},t),((r={})[e.getSplitName()]=e,r))},{})),this._assignmentRegistry},t.prototype.vary=function(t,e){if("object"!=typeof e.variants)throw new Error("must provide variants object to `vary` for "+t);if(!e.context)throw new Error("must provide context to `vary` for "+t);if(!e.defaultVariant&&!1!==e.defaultVariant)throw new Error("must provide defaultVariant to `vary` for "+t);var r=e.defaultVariant.toString(),n=e.variants,i=e.context;if(!n.hasOwnProperty(r))throw new Error("defaultVariant: "+r+" must be represented in variants object");var o=this._getAssignmentFor(t,i),s=new Vt({assignment:o,visitor:this});for(var a in n)n.hasOwnProperty(a)&&(a===r?s.default(a,n[a]):s.when(a,n[a]));s.run(),s.isDefaulted()&&(o.setVariant(s.getDefaultVariant()),o.setUnsynced(!0),o.setContext(i)),this.notifyUnsyncedAssignments()},t.prototype.ab=function(t,e){var r=new wt({splitName:t,trueVariant:e.trueVariant,visitor:this}).getVariants(),n={};n[r.true.toString()]=function(){e.callback(!0)},n[r.false.toString()]=function(){e.callback(!1)},this.vary(t,{context:e.context,variants:n,defaultVariant:r.false})},t.prototype.setErrorLogger=function(t){if("function"!=typeof t)throw new Error("must provide function for errorLogger");this._errorLogger=t},t.prototype.logError=function(t){this._errorLogger.call(null,t)},t.prototype.linkIdentifier=function(t,e){var r=this;return new bt({identifierType:t,value:e,visitorId:this.getId()}).save().then(function(t){r._merge(t),r.notifyUnsyncedAssignments()})},t.prototype.setAnalytics=function(t){if("object"!=typeof t)throw new Error("must provide object for setAnalytics");this.analytics=t},t.prototype.notifyUnsyncedAssignments=function(){this._getUnsyncedAssignments().forEach(this._notify.bind(this))},t.prototype._getUnsyncedAssignments=function(){var t=this.getAssignmentRegistry();return Object.keys(t).reduce(function(e,r){var n=t[r];return n.isUnsynced()&&e.push(n),e},[])},t.prototype._merge=function(t){var e=this.getAssignmentRegistry(),r=t.getAssignmentRegistry();this._id=t.getId(),Object.assign(e,r)},t.prototype._getAssignmentFor=function(t,e){return this.getAssignmentRegistry()[t]||this._generateAssignmentFor(t,e)},t.prototype._generateAssignmentFor=function(t,e){var r=new Rt({visitor:this,splitName:t}).getVariant();r||(this._ttOffline=!0);var i=new n({splitName:t,variant:r,context:e,isUnsynced:!0});return this._assignments.push(i),this._assignmentRegistry=null,i},t.prototype._notify=function(t){try{if(this._ttOffline)return;new _t({visitor:this,assignment:t}).send(),t.setUnsynced(!1)}catch(t){this.logError("test_track notify error: "+t)}},t}(),kt=null,Ut=(new(function(){function t(){this._visitorLoaded=new Promise(function(t){return kt=t})}return t.prototype.initialize=function(t){var e=r.get(mt.getCookieName());return Ot.loadVisitor(e).then(function(e){t&&t.analytics&&e.setAnalytics(t.analytics),t&&t.errorLogger&&e.setErrorLogger(t.errorLogger),t&&"function"==typeof t.onVisitorLoaded&&t.onVisitorLoaded.call(null,e),e.notifyUnsyncedAssignments(),kt&&kt(e)}),this._setCookie(),this._visitorLoaded},t.prototype.vary=function(t,e){return this._visitorLoaded.then(function(r){r.vary(t,e)})},t.prototype.ab=function(t,e){return this._visitorLoaded.then(function(r){r.ab(t,e)})},t.prototype.logIn=function(t,e){var r=this;return this._visitorLoaded.then(function(n){return n.linkIdentifier(t,e).then(function(){r._setCookie(),n.analytics.identify(n.getId())})})},t.prototype.signUp=function(t,e){var r=this;return this._visitorLoaded.then(function(n){return n.linkIdentifier(t,e).then(function(){r._setCookie(),n.analytics.alias(n.getId())})})},t.prototype._setCookie=function(){return this._visitorLoaded.then(function(t){r.set(mt.getCookieName(),t.getId(),{expires:365,path:"/",domain:mt.getCookieDomain()})})},t.prototype.getPublicAPI=function(){var t=this;return{vary:this.vary.bind(this),ab:this.ab.bind(this),logIn:this.logIn.bind(this),signUp:this.signUp.bind(this),initialize:this.initialize.bind(this),_crx:{loadInfo:function(){return t._visitorLoaded.then(function(t){var e={};for(var r in t.getAssignmentRegistry())e[r]=t.getAssignmentRegistry()[r].getVariant();return{visitorId:t.getId(),splitRegistry:mt.getSplitRegistry().asV1Hash(),assignmentRegistry:e}})},persistAssignment:function(e,r,i,o){return t._visitorLoaded.then(function(t){return new vt({visitor:t,username:i,password:o,assignment:new n({splitName:e,variant:r,context:"chrome_extension",isUnsynced:!0})}).persistAssignment()})}}}},t}())).getPublicAPI(),Tt=function(){window.dispatchEvent(new CustomEvent("tt:lib:loaded",{detail:{TestTrack:Ut}}))},Dt=function(){document.body.classList.add("_tt");try{window.dispatchEvent(new CustomEvent("tt:class:added"))}catch(t){}};try{"loading"===document.readyState?document.addEventListener("DOMContentLoaded",Dt):Dt(),Tt(),window.addEventListener("tt:listener:ready",Tt)}catch(t){}return Ut});
|
@@ -12,9 +12,7 @@ module TestTrack::Controller
|
|
12
12
|
class_methods do
|
13
13
|
def require_feature_flag(feature_flag, *args)
|
14
14
|
before_action(*args) do
|
15
|
-
unless test_track_visitor.ab(feature_flag, context: self.class.name.underscore)
|
16
|
-
raise ActionController::RoutingError, 'Not Found'
|
17
|
-
end
|
15
|
+
raise ActionController::RoutingError, 'Not Found' unless test_track_visitor.ab(feature_flag, context: self.class.name.underscore)
|
18
16
|
end
|
19
17
|
end
|
20
18
|
end
|
@@ -6,6 +6,7 @@ module TestTrack::RequiredOptions
|
|
6
6
|
def require_option!(opts, opt_name, my_opts = {})
|
7
7
|
opt_provided = my_opts[:allow_nil] ? opts.key?(opt_name) : opts[opt_name]
|
8
8
|
raise(ArgumentError, "Must provide #{opt_name}") unless opt_provided
|
9
|
+
|
9
10
|
opts.delete(opt_name)
|
10
11
|
end
|
11
12
|
end
|
@@ -19,10 +19,8 @@ class TestTrack::ABConfiguration
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def build_variant_hash
|
22
|
-
if split_variants && split_variants.size > 2
|
23
|
-
|
24
|
-
end
|
25
|
-
{ true: true_variant, false: false_variant }
|
22
|
+
notify_because_ab("configures split with more than 2 variants") if split_variants && split_variants.size > 2
|
23
|
+
{ true: true_variant, false: false_variant } # rubocop:disable Lint/BooleanSymbol
|
26
24
|
end
|
27
25
|
|
28
26
|
def true_variant
|
@@ -30,7 +28,7 @@ class TestTrack::ABConfiguration
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def false_variant
|
33
|
-
@false_variant ||= non_true_variants.present? ? non_true_variants.
|
31
|
+
@false_variant ||= non_true_variants.present? ? non_true_variants.min : false
|
34
32
|
end
|
35
33
|
|
36
34
|
attr_reader :split_name, :split_registry
|
@@ -9,6 +9,7 @@ module TestTrack::Analytics
|
|
9
9
|
def error_handler=(handler)
|
10
10
|
raise ArgumentError, "error_handler must be a lambda" unless handler.lambda?
|
11
11
|
raise ArgumentError, "error_handler must accept 1 argument" unless handler.arity == 1
|
12
|
+
|
12
13
|
@error_handler = handler
|
13
14
|
end
|
14
15
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class TestTrack::ConfigUpdater
|
2
|
-
def initialize(schema_file_path = Rails.root.join('db
|
2
|
+
def initialize(schema_file_path = Rails.root.join('db/test_track_schema.yml'))
|
3
3
|
@schema_file_path = schema_file_path
|
4
4
|
end
|
5
5
|
|
@@ -75,7 +75,7 @@ class TestTrack::ConfigUpdater
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def unpersisted_split_names
|
78
|
-
@
|
78
|
+
@unpersisted_split_names ||= splits.keys - remote_splits.keys
|
79
79
|
end
|
80
80
|
|
81
81
|
def splits
|
@@ -90,7 +90,7 @@ class TestTrack::ConfigUpdater
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def schema_file_hash
|
93
|
-
@
|
93
|
+
@schema_file_hash ||= YAML.safe_load(schema_file_contents) || {}
|
94
94
|
end
|
95
95
|
|
96
96
|
def schema_file_contents
|
@@ -50,26 +50,24 @@ class TestTrack::Fake::SplitRegistry
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def legacy_test_track_schema_yml
|
53
|
-
unless instance_variable_defined?(:@legacy_test_track_schema_yml)
|
54
|
-
@legacy_test_track_schema_yml = _legacy_test_track_schema_yml
|
55
|
-
end
|
53
|
+
@legacy_test_track_schema_yml = _legacy_test_track_schema_yml unless instance_variable_defined?(:@legacy_test_track_schema_yml)
|
56
54
|
@legacy_test_track_schema_yml
|
57
55
|
end
|
58
56
|
|
59
57
|
def _legacy_test_track_schema_yml
|
60
58
|
File.exist?(legacy_test_track_schema_yml_path) &&
|
61
59
|
YAML.load_file(legacy_test_track_schema_yml_path).with_indifferent_access
|
62
|
-
rescue
|
60
|
+
rescue StandardError
|
63
61
|
nil
|
64
62
|
end
|
65
63
|
|
66
64
|
def legacy_test_track_schema_yml_path
|
67
|
-
ENV["TEST_TRACK_SCHEMA_FILE_PATH"] || Rails.root.join('db
|
65
|
+
ENV["TEST_TRACK_SCHEMA_FILE_PATH"] || Rails.root.join('db/test_track_schema.yml').to_s
|
68
66
|
end
|
69
67
|
|
70
68
|
def split_registry_with_deterministic_weights
|
71
69
|
splits = split_hash.each_with_object({}) do |(split_name, weighting_registry), result|
|
72
|
-
default_variant = weighting_registry.keys.
|
70
|
+
default_variant = weighting_registry.keys.min
|
73
71
|
|
74
72
|
adjusted_weights = { default_variant => 100 }
|
75
73
|
weighting_registry.except(default_variant).each_key do |variant|
|
@@ -24,9 +24,7 @@ class TestTrack::JobSession
|
|
24
24
|
|
25
25
|
def notify_unsynced_assignments!
|
26
26
|
identity_visitor_map.each_value do |visitor|
|
27
|
-
if visitor.loaded? && visitor.unsynced_assignments.present?
|
28
|
-
TestTrack::ThreadedVisitorNotifier.new(visitor).notify
|
29
|
-
end
|
27
|
+
TestTrack::ThreadedVisitorNotifier.new(visitor).notify if visitor.loaded? && visitor.unsynced_assignments.present?
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
@@ -4,7 +4,7 @@ class TestTrack::LazyVisitorByIdentity
|
|
4
4
|
end
|
5
5
|
|
6
6
|
def loaded?
|
7
|
-
@
|
7
|
+
@__visitor__.present?
|
8
8
|
end
|
9
9
|
|
10
10
|
def id_loaded?
|
@@ -13,8 +13,12 @@ class TestTrack::LazyVisitorByIdentity
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
-
def method_missing(method, *args, &block)
|
17
|
-
__visitor__.
|
16
|
+
def method_missing(method, *args, &block)
|
17
|
+
if __visitor__.respond_to?(method)
|
18
|
+
__visitor__.send(method, *args, &block)
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def respond_to_missing?(method, include_private = false)
|
@@ -22,7 +26,7 @@ class TestTrack::LazyVisitorByIdentity
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def __visitor__
|
25
|
-
@
|
29
|
+
@__visitor__ ||= __load_visitor__
|
26
30
|
end
|
27
31
|
|
28
32
|
def __load_visitor__
|
@@ -22,6 +22,7 @@ module TestTrack::MisconfigurationNotifier
|
|
22
22
|
class Airbrake
|
23
23
|
def notify(msg)
|
24
24
|
raise "Aibrake was configured but not found" unless defined?(::Airbrake)
|
25
|
+
|
25
26
|
if ::Airbrake.respond_to?(:notify_or_ignore)
|
26
27
|
::Airbrake.notify_or_ignore(StandardError.new, error_message: msg)
|
27
28
|
else
|
@@ -28,6 +28,7 @@ class TestTrack::NotifyAssignmentJob
|
|
28
28
|
def maybe_track
|
29
29
|
return "failure" unless TestTrack.enabled?
|
30
30
|
return "success" if skip_analytics_event?
|
31
|
+
|
31
32
|
result = TestTrack.analytics.track(TestTrack::AnalyticsEvent.new(visitor_id, assignment))
|
32
33
|
result ? "success" : "failure"
|
33
34
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TestTrack::Remote::Identifier
|
2
2
|
include TestTrack::RemoteModel
|
3
3
|
|
4
|
-
collection_path '
|
4
|
+
collection_path 'api/v1/identifier'
|
5
5
|
|
6
6
|
has_one :remote_visitor, data_key: :visitor, class_name: "TestTrack::Remote::Visitor"
|
7
7
|
|
@@ -21,6 +21,7 @@ class TestTrack::Remote::Identifier
|
|
21
21
|
|
22
22
|
def visitor_opts!
|
23
23
|
raise("Visitor data unavailable until you save this identifier.") unless attributes[:remote_visitor]
|
24
|
+
|
24
25
|
{ id: remote_visitor.id, assignments: remote_visitor.assignments }
|
25
26
|
end
|
26
27
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TestTrack::Remote::SplitDetail
|
2
2
|
include TestTrack::RemoteModel
|
3
3
|
|
4
|
-
collection_path '
|
4
|
+
collection_path 'api/v1/split_details'
|
5
5
|
|
6
6
|
attributes :name, :hypothesis, :assignment_criteria, :description, :owner, :location, :platform, :variant_details
|
7
7
|
|
@@ -10,7 +10,7 @@ class TestTrack::Remote::SplitDetail
|
|
10
10
|
if faked?
|
11
11
|
new(fake_instance_attributes(name))
|
12
12
|
else
|
13
|
-
get("
|
13
|
+
get("api/v1/split_details/#{name}")
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -3,7 +3,7 @@ class TestTrack::Remote::SplitRegistry
|
|
3
3
|
|
4
4
|
CACHE_KEY = 'test_track_split_registry'.freeze
|
5
5
|
|
6
|
-
collection_path '
|
6
|
+
collection_path 'api/v3/builds/:build_timestamp/split_registry'
|
7
7
|
|
8
8
|
class << self
|
9
9
|
def fake_instance_attributes(_)
|
@@ -15,7 +15,7 @@ class TestTrack::Remote::SplitRegistry
|
|
15
15
|
if faked?
|
16
16
|
new(fake_instance_attributes(nil))
|
17
17
|
else
|
18
|
-
get(
|
18
|
+
get("api/v3/builds/#{TestTrack.build_timestamp}/split_registry")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class TestTrack::Remote::Visitor
|
2
2
|
include TestTrack::RemoteModel
|
3
3
|
|
4
|
-
collection_path '
|
4
|
+
collection_path 'api/v1/visitors'
|
5
5
|
|
6
6
|
has_many :assignments
|
7
7
|
|
@@ -13,7 +13,7 @@ class TestTrack::Remote::Visitor
|
|
13
13
|
if faked?
|
14
14
|
new(fake_instance_attributes(nil))
|
15
15
|
else
|
16
|
-
get("
|
16
|
+
get("api/v1/identifier_types/#{identifier_type}/identifiers/#{identifier_value}/visitor")
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -8,7 +8,7 @@ class TestTrack::Remote::VisitorDetail
|
|
8
8
|
if faked?
|
9
9
|
new(fake_instance_attributes(nil))
|
10
10
|
else
|
11
|
-
get("
|
11
|
+
get("api/v1/identifier_types/#{identifier_type}/identifiers/#{identifier_value}/visitor_detail")
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -27,9 +27,9 @@ class TestTrack::SplitRegistry
|
|
27
27
|
registry_hash && registry_hash['splits'][split_name] && registry_hash['splits'][split_name]['weights'].freeze
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
registry_hash && registry_hash['splits'].
|
32
|
-
|
30
|
+
def to_hash
|
31
|
+
registry_hash && registry_hash['splits'].transform_values do |v|
|
32
|
+
{ weights: v['weights'], feature_gate: v['feature_gate'] }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -21,14 +21,12 @@ class TestTrack::ThreadedVisitorNotifier
|
|
21
21
|
|
22
22
|
def new_thread_with_request_store
|
23
23
|
Thread.new(RequestStore.store) do |original_store|
|
24
|
-
begin
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
RequestStore.clear!
|
31
|
-
end
|
24
|
+
RequestStore.begin!
|
25
|
+
RequestStore.store.merge!(original_store)
|
26
|
+
yield
|
27
|
+
ensure
|
28
|
+
RequestStore.end!
|
29
|
+
RequestStore.clear!
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
@@ -14,12 +14,10 @@ class TestTrack::UnsyncedAssignmentsNotifier
|
|
14
14
|
def notify
|
15
15
|
assignments.each do |assignment|
|
16
16
|
build_notify_assignment_job(assignment).tap do |job|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
Delayed::Job.enqueue(build_notify_assignment_job(assignment))
|
22
|
-
end
|
17
|
+
job.perform
|
18
|
+
rescue *TestTrack::SERVER_ERRORS => e
|
19
|
+
Rails.logger.error "TestTrack failed to notify unsynced assignments, retrying. #{e}"
|
20
|
+
Delayed::Job.enqueue(build_notify_assignment_job(assignment))
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -18,6 +18,7 @@ class TestTrack::VaryDSL
|
|
18
18
|
|
19
19
|
def when(*variants, &block)
|
20
20
|
raise ArgumentError, "must provide at least one variant" if variants.blank?
|
21
|
+
|
21
22
|
variants.each do |variant|
|
22
23
|
assign_behavior_to_variant(variant, block)
|
23
24
|
end
|
@@ -25,6 +26,7 @@ class TestTrack::VaryDSL
|
|
25
26
|
|
26
27
|
def default(variant, &block)
|
27
28
|
raise ArgumentError, "cannot provide more than one `default`" unless default_variant.nil?
|
29
|
+
|
28
30
|
@default_variant = assign_behavior_to_variant(variant, block)
|
29
31
|
end
|
30
32
|
|
@@ -57,6 +59,7 @@ class TestTrack::VaryDSL
|
|
57
59
|
variant = variant.to_s
|
58
60
|
|
59
61
|
raise ArgumentError, "must provide block for #{variant}" unless behavior_proc
|
62
|
+
|
60
63
|
notify_because_vary(<<-MESSAGE) if variant_behaviors.include?(variant)
|
61
64
|
configures variant "#{variant}" more than once.
|
62
65
|
This will raise an error in the next version of test_track_rails_client.
|
@@ -93,6 +96,7 @@ class TestTrack::VaryDSL
|
|
93
96
|
raise ArgumentError, "must provide exactly one `default`" unless default_variant
|
94
97
|
raise ArgumentError, "must provide at least one `when`" unless variant_behaviors.size >= 2
|
95
98
|
return true unless split_variants
|
99
|
+
|
96
100
|
missing_variants = split_variants - variant_behaviors.keys
|
97
101
|
notify_because_vary("does not configure variants #{missing_variants.to_sentence}") && false unless missing_variants.empty?
|
98
102
|
end
|
@@ -23,6 +23,7 @@ class TestTrack::Visitor
|
|
23
23
|
raise "unknown opts: #{opts.keys.to_sentence}" if opts.present?
|
24
24
|
|
25
25
|
raise ArgumentError, "must provide block to `vary` for #{split_name}" unless block_given?
|
26
|
+
|
26
27
|
v = TestTrack::VaryDSL.new(assignment: assignment_for(split_name), context: context, split_registry: split_registry)
|
27
28
|
yield v
|
28
29
|
v.send :run
|
@@ -38,18 +39,18 @@ class TestTrack::Visitor
|
|
38
39
|
ab_configuration = TestTrack::ABConfiguration.new split_name: split_name, true_variant: true_variant, split_registry: split_registry
|
39
40
|
|
40
41
|
vary(split_name, context: context) do |v|
|
41
|
-
v.when ab_configuration.variants[:true] do
|
42
|
+
v.when ab_configuration.variants[:true] do # rubocop:disable Lint/BooleanSymbol
|
42
43
|
true
|
43
44
|
end
|
44
|
-
v.default ab_configuration.variants[:false] do
|
45
|
+
v.default ab_configuration.variants[:false] do # rubocop:disable Lint/BooleanSymbol
|
45
46
|
false
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
51
|
def assignment_registry
|
51
|
-
@assignment_registry ||= assignments.
|
52
|
-
|
52
|
+
@assignment_registry ||= assignments.index_by do |assignment|
|
53
|
+
assignment.split_name
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
@@ -28,8 +28,9 @@ class TestTrack::WebSession
|
|
28
28
|
url: TestTrack.url,
|
29
29
|
cookieDomain: cookie_domain,
|
30
30
|
cookieName: visitor_cookie_name,
|
31
|
-
|
32
|
-
assignments: current_visitor.assignment_json
|
31
|
+
splits: current_visitor.split_registry.to_hash,
|
32
|
+
assignments: current_visitor.assignment_json,
|
33
|
+
experienceSamplingWeight: current_visitor.split_registry.experience_sampling_weight
|
33
34
|
}
|
34
35
|
end
|
35
36
|
|
@@ -58,6 +59,7 @@ class TestTrack::WebSession
|
|
58
59
|
|
59
60
|
If your app doesn't support authentication, set it to `:none`.
|
60
61
|
ERROR
|
62
|
+
|
61
63
|
identity = controller.class.test_track_identity
|
62
64
|
controller.send(identity) unless identity == :none
|
63
65
|
end
|
@@ -92,7 +94,7 @@ class TestTrack::WebSession
|
|
92
94
|
end
|
93
95
|
|
94
96
|
def _cookie_domain
|
95
|
-
if bare_ip_address? || fully_qualified_cookie_domain_enabled?
|
97
|
+
if bare_ip_address? || request.local? || fully_qualified_cookie_domain_enabled?
|
96
98
|
request.host
|
97
99
|
else
|
98
100
|
wildcard_domain
|
@@ -34,9 +34,7 @@ class TestTrack::WebSessionVisitorRepository
|
|
34
34
|
|
35
35
|
def notify_unsynced_assignments!
|
36
36
|
all.each do |visitor|
|
37
|
-
if visitor.loaded? && visitor.unsynced_assignments.present?
|
38
|
-
TestTrack::ThreadedVisitorNotifier.new(visitor).notify
|
39
|
-
end
|
37
|
+
TestTrack::ThreadedVisitorNotifier.new(visitor).notify if visitor.loaded? && visitor.unsynced_assignments.present?
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -0,0 +1 @@
|
|
1
|
+
TestTrack.set_build_timestamp! unless ENV['SKIP_TESTTRACK_SET_BUILD_TIMESTAMP'] == '1'
|
@@ -10,6 +10,24 @@ namespace :test_track do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
desc 'Generates build timestamp for fetching point-in-time split registries'
|
14
|
+
task generate_build_timestamp: :environment do
|
15
|
+
cli = TesttrackCli.instance
|
16
|
+
|
17
|
+
result = cli.call('generate_build_timestamp')
|
18
|
+
exit(result.exitstatus) unless result.success?
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Sets an environment variable to block build timestamp generation on application initialization'
|
22
|
+
task :skip_set_build_timestamp do # rubocop:disable Rails/RakeEnvironment
|
23
|
+
ENV['SKIP_TESTTRACK_SET_BUILD_TIMESTAMP'] = '1'
|
24
|
+
end
|
25
|
+
|
26
|
+
desc 'Removes the testtrack/build_timestamp file'
|
27
|
+
task remove_build_timestamp: :environment do
|
28
|
+
File.delete('testtrack/build_timestamp') if File.exist?('testtrack/build_timestamp')
|
29
|
+
end
|
30
|
+
|
13
31
|
namespace :schema do
|
14
32
|
desc 'Load schema.yml state into TestTrack server'
|
15
33
|
task load: :environment do
|
@@ -28,6 +46,9 @@ namespace :test_track do
|
|
28
46
|
end
|
29
47
|
end
|
30
48
|
|
49
|
+
task 'assets:clobber' => ['test_track:remove_build_timestamp']
|
50
|
+
task 'assets:environment' => ['test_track:skip_set_build_timestamp']
|
51
|
+
task 'assets:precompile' => ['test_track:generate_build_timestamp']
|
31
52
|
task 'db:schema:load' => ['test_track:schema:load']
|
32
53
|
task 'db:structure:load' => ['test_track:schema:load']
|
33
54
|
task 'db:migrate' => ['test_track:migrate']
|
data/lib/test_track.rb
CHANGED
@@ -16,6 +16,8 @@ module TestTrack
|
|
16
16
|
module_function
|
17
17
|
|
18
18
|
SERVER_ERRORS = [Faraday::ConnectionFailed, Faraday::TimeoutError, Her::Errors::RemoteServerError].freeze
|
19
|
+
BUILD_TIMESTAMP_FILE_PATH = 'testtrack/build_timestamp'.freeze
|
20
|
+
BUILD_TIMESTAMP_REGEX = /\A\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(.\d+)?([+-][0-2]\d:[0-5]\d|Z)\z/.freeze
|
19
21
|
|
20
22
|
mattr_accessor :enabled_override, :app_name
|
21
23
|
|
@@ -52,6 +54,26 @@ module TestTrack
|
|
52
54
|
@misconfiguration_notifier_class_name = notifier_class_name
|
53
55
|
end
|
54
56
|
|
57
|
+
def build_timestamp # rubocop:disable Metrics/MethodLength
|
58
|
+
@build_timestamp ||= begin
|
59
|
+
timestamp = _build_timestamp
|
60
|
+
|
61
|
+
if Rails.env.test? || Rails.env.development?
|
62
|
+
Time.zone.now.iso8601
|
63
|
+
elsif timestamp.present?
|
64
|
+
unless BUILD_TIMESTAMP_REGEX.match?(timestamp)
|
65
|
+
raise "./testtrack/build_timestamp is not a valid ISO 8601 timestamp, got '#{timestamp}'"
|
66
|
+
end
|
67
|
+
|
68
|
+
timestamp
|
69
|
+
else
|
70
|
+
raise 'TestTrack failed to load the required build timestamp. ' \
|
71
|
+
'Ensure `test_track:generate_build_timestamp` task is run in `assets:precompile` and the build timestamp file is present.'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
alias set_build_timestamp! build_timestamp
|
76
|
+
|
55
77
|
private
|
56
78
|
|
57
79
|
def analytics_instance
|
@@ -95,6 +117,7 @@ module TestTrack
|
|
95
117
|
|
96
118
|
def url
|
97
119
|
return nil unless private_url
|
120
|
+
|
98
121
|
full_uri = URI.parse(private_url)
|
99
122
|
full_uri.user = nil
|
100
123
|
full_uri.password = nil
|
@@ -105,6 +128,10 @@ module TestTrack
|
|
105
128
|
ENV['TEST_TRACK_API_URL']
|
106
129
|
end
|
107
130
|
|
131
|
+
def _build_timestamp
|
132
|
+
File.read(BUILD_TIMESTAMP_FILE_PATH).chomp.presence if File.exist?(BUILD_TIMESTAMP_FILE_PATH)
|
133
|
+
end
|
134
|
+
|
108
135
|
def enabled?
|
109
136
|
enabled_override.nil? ? !Rails.env.test? : enabled_override
|
110
137
|
end
|
@@ -2,13 +2,15 @@ require 'delayed_job'
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'airbrake'
|
5
|
-
rescue LoadError
|
5
|
+
rescue LoadError
|
6
|
+
# no-op
|
6
7
|
end
|
7
8
|
|
8
9
|
unless defined?(Delayed::Plugins::Airbrake) && Delayed::Worker.plugins.include?(Delayed::Plugins::Airbrake)
|
9
10
|
begin
|
10
11
|
require 'delayed-plugins-airbrake'
|
11
|
-
rescue LoadError
|
12
|
+
rescue LoadError
|
13
|
+
# no-op
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test_track_rails_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.
|
4
|
+
version: 4.0.0.rc3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan O'Neill
|
@@ -10,10 +10,10 @@ authors:
|
|
10
10
|
- John Mileham
|
11
11
|
- Alan Norton
|
12
12
|
- Sam Moore
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2020-12-04 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: delayed_job
|
@@ -134,7 +134,7 @@ dependencies:
|
|
134
134
|
version: '4.1'
|
135
135
|
- - "<"
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: '
|
137
|
+
version: '7.0'
|
138
138
|
type: :runtime
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -144,7 +144,7 @@ dependencies:
|
|
144
144
|
version: '4.1'
|
145
145
|
- - "<"
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version: '
|
147
|
+
version: '7.0'
|
148
148
|
- !ruby/object:Gem::Dependency
|
149
149
|
name: request_store
|
150
150
|
requirement: !ruby/object:Gem::Requirement
|
@@ -161,20 +161,132 @@ dependencies:
|
|
161
161
|
version: '1.3'
|
162
162
|
- !ruby/object:Gem::Dependency
|
163
163
|
name: appraisal
|
164
|
+
requirement: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
type: :development
|
170
|
+
prerelease: false
|
171
|
+
version_requirements: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
- !ruby/object:Gem::Dependency
|
177
|
+
name: pry-rails
|
178
|
+
requirement: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
type: :development
|
184
|
+
prerelease: false
|
185
|
+
version_requirements: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
- !ruby/object:Gem::Dependency
|
191
|
+
name: rails-controller-testing
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
type: :development
|
198
|
+
prerelease: false
|
199
|
+
version_requirements: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - ">="
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
- !ruby/object:Gem::Dependency
|
205
|
+
name: rspec-rails
|
206
|
+
requirement: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: '0'
|
211
|
+
type: :development
|
212
|
+
prerelease: false
|
213
|
+
version_requirements: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - ">="
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
218
|
+
- !ruby/object:Gem::Dependency
|
219
|
+
name: rubocop
|
164
220
|
requirement: !ruby/object:Gem::Requirement
|
165
221
|
requirements:
|
166
222
|
- - "~>"
|
167
223
|
- !ruby/object:Gem::Version
|
168
|
-
version:
|
224
|
+
version: 0.81.0
|
169
225
|
type: :development
|
170
226
|
prerelease: false
|
171
227
|
version_requirements: !ruby/object:Gem::Requirement
|
172
228
|
requirements:
|
173
229
|
- - "~>"
|
174
230
|
- !ruby/object:Gem::Version
|
175
|
-
version:
|
231
|
+
version: 0.81.0
|
176
232
|
- !ruby/object:Gem::Dependency
|
177
|
-
name:
|
233
|
+
name: rubocop-performance
|
234
|
+
requirement: !ruby/object:Gem::Requirement
|
235
|
+
requirements:
|
236
|
+
- - ">="
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
version: '0'
|
239
|
+
type: :development
|
240
|
+
prerelease: false
|
241
|
+
version_requirements: !ruby/object:Gem::Requirement
|
242
|
+
requirements:
|
243
|
+
- - ">="
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: '0'
|
246
|
+
- !ruby/object:Gem::Dependency
|
247
|
+
name: rubocop-rails
|
248
|
+
requirement: !ruby/object:Gem::Requirement
|
249
|
+
requirements:
|
250
|
+
- - ">="
|
251
|
+
- !ruby/object:Gem::Version
|
252
|
+
version: '0'
|
253
|
+
type: :development
|
254
|
+
prerelease: false
|
255
|
+
version_requirements: !ruby/object:Gem::Requirement
|
256
|
+
requirements:
|
257
|
+
- - ">="
|
258
|
+
- !ruby/object:Gem::Version
|
259
|
+
version: '0'
|
260
|
+
- !ruby/object:Gem::Dependency
|
261
|
+
name: shoulda-matchers
|
262
|
+
requirement: !ruby/object:Gem::Requirement
|
263
|
+
requirements:
|
264
|
+
- - ">="
|
265
|
+
- !ruby/object:Gem::Version
|
266
|
+
version: '2.8'
|
267
|
+
type: :development
|
268
|
+
prerelease: false
|
269
|
+
version_requirements: !ruby/object:Gem::Requirement
|
270
|
+
requirements:
|
271
|
+
- - ">="
|
272
|
+
- !ruby/object:Gem::Version
|
273
|
+
version: '2.8'
|
274
|
+
- !ruby/object:Gem::Dependency
|
275
|
+
name: simplecov
|
276
|
+
requirement: !ruby/object:Gem::Requirement
|
277
|
+
requirements:
|
278
|
+
- - ">="
|
279
|
+
- !ruby/object:Gem::Version
|
280
|
+
version: '0'
|
281
|
+
type: :development
|
282
|
+
prerelease: false
|
283
|
+
version_requirements: !ruby/object:Gem::Requirement
|
284
|
+
requirements:
|
285
|
+
- - ">="
|
286
|
+
- !ruby/object:Gem::Version
|
287
|
+
version: '0'
|
288
|
+
- !ruby/object:Gem::Dependency
|
289
|
+
name: sqlite3
|
178
290
|
requirement: !ruby/object:Gem::Requirement
|
179
291
|
requirements:
|
180
292
|
- - ">="
|
@@ -205,16 +317,16 @@ dependencies:
|
|
205
317
|
name: webmock
|
206
318
|
requirement: !ruby/object:Gem::Requirement
|
207
319
|
requirements:
|
208
|
-
- - "
|
320
|
+
- - ">="
|
209
321
|
- !ruby/object:Gem::Version
|
210
|
-
version:
|
322
|
+
version: '0'
|
211
323
|
type: :development
|
212
324
|
prerelease: false
|
213
325
|
version_requirements: !ruby/object:Gem::Requirement
|
214
326
|
requirements:
|
215
|
-
- - "
|
327
|
+
- - ">="
|
216
328
|
- !ruby/object:Gem::Version
|
217
|
-
version:
|
329
|
+
version: '0'
|
218
330
|
description: Easy split testing and feature flagging for Rails with TestTrack server
|
219
331
|
email:
|
220
332
|
- ryan.oneill@betterment.com
|
@@ -285,6 +397,7 @@ files:
|
|
285
397
|
- app/views/tt/api/v1/split_details/show.json.jbuilder
|
286
398
|
- app/views/tt/api/v1/visitors/_show.json.jbuilder
|
287
399
|
- app/views/tt/api/v1/visitors/show.json.jbuilder
|
400
|
+
- config/initializers/set_build_timestamp.rb
|
288
401
|
- config/initializers/test_track_api.rb
|
289
402
|
- config/routes.rb
|
290
403
|
- lib/generators/test_track/migration_generator.rb
|
@@ -341,7 +454,7 @@ homepage: https://github.com/Betterment
|
|
341
454
|
licenses:
|
342
455
|
- MIT
|
343
456
|
metadata: {}
|
344
|
-
post_install_message:
|
457
|
+
post_install_message:
|
345
458
|
rdoc_options: []
|
346
459
|
require_paths:
|
347
460
|
- lib
|
@@ -349,16 +462,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
349
462
|
requirements:
|
350
463
|
- - ">="
|
351
464
|
- !ruby/object:Gem::Version
|
352
|
-
version: 2.
|
465
|
+
version: 2.5.0
|
353
466
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
354
467
|
requirements:
|
355
468
|
- - ">"
|
356
469
|
- !ruby/object:Gem::Version
|
357
470
|
version: 1.3.1
|
358
471
|
requirements: []
|
359
|
-
|
360
|
-
|
361
|
-
signing_key:
|
472
|
+
rubygems_version: 3.1.4
|
473
|
+
signing_key:
|
362
474
|
specification_version: 4
|
363
475
|
summary: Rails client for TestTrack
|
364
476
|
test_files: []
|