upgini 1.1.274a3388.post2__tar.gz → 1.1.275__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of upgini might be problematic. Click here for more details.

Files changed (85) hide show
  1. {upgini-1.1.274a3388.post2/src/upgini.egg-info → upgini-1.1.275}/PKG-INFO +2 -2
  2. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/setup.py +2 -2
  3. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/ads.py +6 -2
  4. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/date.py +11 -19
  5. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/feature.py +1 -70
  6. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/operand.py +2 -10
  7. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/data_source/data_source_publisher.py +1 -1
  8. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/dataset.py +4 -3
  9. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/features_enricher.py +70 -29
  10. upgini-1.1.275/src/upgini/fingerprint.js +8 -0
  11. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/metrics.py +12 -0
  12. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/normalizer/phone_normalizer.py +2 -2
  13. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/resource_bundle/strings.properties +2 -1
  14. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/__init__.py +3 -2
  15. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/country_utils.py +2 -2
  16. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/datetime_utils.py +7 -4
  17. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/email_utils.py +2 -2
  18. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/features_validator.py +2 -1
  19. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/target_utils.py +1 -1
  20. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/track_info.py +25 -13
  21. {upgini-1.1.274a3388.post2 → upgini-1.1.275/src/upgini.egg-info}/PKG-INFO +2 -2
  22. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini.egg-info/SOURCES.txt +1 -0
  23. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini.egg-info/requires.txt +1 -1
  24. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_autofe_operands.py +2 -44
  25. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_features_enricher.py +18 -13
  26. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/LICENSE +0 -0
  27. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/README.md +0 -0
  28. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/pyproject.toml +0 -0
  29. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/setup.cfg +0 -0
  30. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/__init__.py +0 -0
  31. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/ads_management/__init__.py +0 -0
  32. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/ads_management/ads_manager.py +0 -0
  33. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/__init__.py +0 -0
  34. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/all_operands.py +0 -0
  35. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/binary.py +0 -0
  36. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/groupby.py +0 -0
  37. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/unary.py +0 -0
  38. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/autofe/vector.py +0 -0
  39. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/data_source/__init__.py +0 -0
  40. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/errors.py +0 -0
  41. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/http.py +0 -0
  42. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/mdc/__init__.py +0 -0
  43. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/mdc/context.py +0 -0
  44. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/metadata.py +0 -0
  45. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/normalizer/__init__.py +0 -0
  46. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/resource_bundle/__init__.py +0 -0
  47. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/resource_bundle/exceptions.py +0 -0
  48. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/resource_bundle/strings_widget.properties +0 -0
  49. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/sampler/__init__.py +0 -0
  50. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/sampler/base.py +0 -0
  51. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/sampler/random_under_sampler.py +0 -0
  52. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/sampler/utils.py +0 -0
  53. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/search_task.py +0 -0
  54. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/spinner.py +0 -0
  55. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/base_search_key_detector.py +0 -0
  56. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/blocked_time_series.py +0 -0
  57. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/custom_loss_utils.py +0 -0
  58. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/cv_utils.py +0 -0
  59. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/deduplicate_utils.py +0 -0
  60. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/display_utils.py +0 -0
  61. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/fallback_progress_bar.py +0 -0
  62. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/format.py +0 -0
  63. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/ip_utils.py +0 -0
  64. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/phone_utils.py +0 -0
  65. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/postal_code_utils.py +0 -0
  66. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/progress_bar.py +0 -0
  67. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/sklearn_ext.py +0 -0
  68. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/utils/warning_counter.py +0 -0
  69. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini/version_validator.py +0 -0
  70. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini.egg-info/dependency_links.txt +0 -0
  71. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/src/upgini.egg-info/top_level.txt +0 -0
  72. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_binary_dataset.py +0 -0
  73. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_blocked_time_series.py +0 -0
  74. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_categorical_dataset.py +0 -0
  75. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_continuous_dataset.py +0 -0
  76. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_country_utils.py +0 -0
  77. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_custom_loss_utils.py +0 -0
  78. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_datetime_utils.py +0 -0
  79. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_email_utils.py +0 -0
  80. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_etalon_validation.py +0 -0
  81. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_metrics.py +0 -0
  82. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_phone_utils.py +0 -0
  83. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_postal_code_utils.py +0 -0
  84. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_target_utils.py +0 -0
  85. {upgini-1.1.274a3388.post2 → upgini-1.1.275}/tests/test_widget.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: upgini
3
- Version: 1.1.274a3388.post2
3
+ Version: 1.1.275
4
4
  Summary: Intelligent data search & enrichment for Machine Learning
5
5
  Home-page: https://upgini.com/
6
6
  Author: Upgini Developers
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
29
  Requires-Dist: python-dateutil>=2.8.0
30
30
  Requires-Dist: requests>=2.8.0
31
- Requires-Dist: pandas<2.0.0,>=1.1.0
31
+ Requires-Dist: pandas<3.0.0,>=1.1.0
32
32
  Requires-Dist: numpy>=1.19.0
33
33
  Requires-Dist: scikit-learn>=1.3.0
34
34
  Requires-Dist: pydantic<2.0.0,>=1.8.2
@@ -40,7 +40,7 @@ def send_log(msg: str):
40
40
 
41
41
 
42
42
  here = Path(__file__).parent.resolve()
43
- version = "1.1.274a3388-2"
43
+ version = "1.1.275"
44
44
  try:
45
45
  send_log(f"Start setup PyLib version {version}")
46
46
  setup(
@@ -77,7 +77,7 @@ try:
77
77
  install_requires=[
78
78
  "python-dateutil>=2.8.0",
79
79
  "requests>=2.8.0",
80
- "pandas>=1.1.0,<2.0.0",
80
+ "pandas>=1.1.0,<3.0.0",
81
81
  "numpy>=1.19.0",
82
82
  "scikit-learn>=1.3.0",
83
83
  "pydantic>=1.8.2,<2.0.0",
@@ -5,7 +5,7 @@ from typing import Dict, Optional
5
5
 
6
6
  import numpy as np
7
7
  import pandas as pd
8
- from pandas.api.types import is_string_dtype
8
+ from pandas.api.types import is_object_dtype, is_string_dtype
9
9
 
10
10
  from upgini import SearchKey
11
11
  from upgini.http import get_rest_client
@@ -34,7 +34,11 @@ def upload_user_ads(name: str, df: pd.DataFrame, search_keys: Dict[str, SearchKe
34
34
  if df[column_name].notnull().sum() < min_valid_rows_count:
35
35
  raise ValueError(bundle.get("ads_upload_to_many_empty_rows"))
36
36
  meaning_type = search_keys[column_name].value
37
- if meaning_type == FileColumnMeaningType.MSISDN and not is_string_dtype(df[column_name]):
37
+ if (
38
+ meaning_type == FileColumnMeaningType.MSISDN
39
+ and not is_string_dtype(df[column_name])
40
+ and not is_object_dtype(df[column_name])
41
+ ):
38
42
  df[column_name] = df[column_name].values.astype(np.int64).astype("string") # type: ignore
39
43
  else:
40
44
  meaning_type = FileColumnMeaningType.FEATURE
@@ -1,9 +1,10 @@
1
- from typing import Any, List, Optional, Union
1
+ from typing import Any, Optional, Union
2
2
  import numpy as np
3
3
  import pandas as pd
4
4
  from pydantic import BaseModel
5
+ from pandas.core.arrays.timedeltas import TimedeltaArray
5
6
 
6
- from upgini.autofe.operand import MultiOperand, Operand, PandasOperand
7
+ from upgini.autofe.operand import PandasOperand
7
8
 
8
9
 
9
10
  class DateDiffMixin(BaseModel):
@@ -24,7 +25,6 @@ class DateDiff(PandasOperand, DateDiffMixin):
24
25
  name = "date_diff"
25
26
  is_binary = True
26
27
  has_symmetry_importance = True
27
- common_type = "date_diff"
28
28
 
29
29
  def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
30
30
  left = self._convert_to_date(left, self.left_unit)
@@ -40,7 +40,6 @@ class DateDiffType2(PandasOperand, DateDiffMixin):
40
40
  name = "date_diff_type2"
41
41
  is_binary = True
42
42
  has_symmetry_importance = True
43
- common_type = "date_diff"
44
43
 
45
44
  def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
46
45
  left = self._convert_to_date(left, self.left_unit)
@@ -48,6 +47,7 @@ class DateDiffType2(PandasOperand, DateDiffMixin):
48
47
  future = right + (left.dt.year - right.dt.year).apply(
49
48
  lambda y: np.datetime64("NaT") if np.isnan(y) else pd.tseries.offsets.DateOffset(years=y)
50
49
  )
50
+ future = pd.to_datetime(future)
51
51
  before = future[future < left]
52
52
  future[future < left] = before + pd.tseries.offsets.DateOffset(years=1)
53
53
  diff = (future - left) / np.timedelta64(1, self.diff_unit)
@@ -62,7 +62,6 @@ class DateListDiff(PandasOperand, DateDiffMixin):
62
62
  is_binary = True
63
63
  has_symmetry_importance = True
64
64
  aggregation: str
65
- common_type = "date_diff_list"
66
65
 
67
66
  def __init__(self, **data: Any) -> None:
68
67
  if "name" not in data:
@@ -75,8 +74,13 @@ class DateListDiff(PandasOperand, DateDiffMixin):
75
74
 
76
75
  return pd.Series(left - right.values).apply(lambda x: self._agg(self._diff(x)))
77
76
 
78
- def _diff(self, x):
79
- x = x / np.timedelta64(1, self.diff_unit)
77
+ def _diff(self, x: TimedeltaArray):
78
+ if self.diff_unit == "Y":
79
+ x = (x / 365 / 24 / 60 / 60 / 10**9).astype(int)
80
+ elif self.diff_unit == "M":
81
+ raise Exception("Unsupported difference unit: Month")
82
+ else:
83
+ x = x / np.timedelta64(1, self.diff_unit)
80
84
  return x[x > 0]
81
85
 
82
86
  def _agg(self, x):
@@ -89,9 +93,6 @@ class DateListDiff(PandasOperand, DateDiffMixin):
89
93
 
90
94
  return method(x) if len(x) > 0 else default
91
95
 
92
- def make_multi_operand(self, operands: List[Operand]) -> Optional[MultiOperand]:
93
- return DateListDiffMulti(children=operands, aggregation="")
94
-
95
96
 
96
97
  class DateListDiffBounded(DateListDiff):
97
98
  lower_bound: Optional[int]
@@ -114,12 +115,3 @@ class DateListDiffBounded(DateListDiff):
114
115
  def _agg(self, x):
115
116
  x = x[(x >= (self.lower_bound or -np.inf)) & (x < (self.upper_bound or np.inf))]
116
117
  return super()._agg(x)
117
-
118
-
119
- class DateListDiffMulti(DateListDiff, MultiOperand):
120
- def calculate_binary(self, left: pd.Series, right: pd.Series) -> pd.Series:
121
- left = self._convert_to_date(left, self.left_unit)
122
- right = right.apply(lambda x: pd.arrays.DatetimeArray(self._convert_to_date(x, self.right_unit)))
123
-
124
- diff = pd.Series(left - right.values).apply(self._diff)
125
- return diff.apply(lambda x: [c._agg(x) for c in self.children])
@@ -1,15 +1,13 @@
1
1
  import hashlib
2
2
  import itertools
3
- import operator
4
3
  from typing import Dict, List, Optional, Tuple, Union
5
4
 
6
- from more_itertools import map_reduce
7
5
  import numpy as np
8
6
  import pandas as pd
9
7
  from pandas._typing import DtypeObj
10
8
 
11
9
  from upgini.autofe.all_operands import find_op
12
- from upgini.autofe.operand import MultiOperand, Operand, PandasOperand
10
+ from upgini.autofe.operand import Operand, PandasOperand
13
11
 
14
12
 
15
13
  class Column:
@@ -31,9 +29,6 @@ class Column:
31
29
  else:
32
30
  return feature_name[2:last_component_idx]
33
31
 
34
- def get_display_name(self, **kwargs):
35
- return self.name
36
-
37
32
  def delete_data(self):
38
33
  self.data = None
39
34
 
@@ -162,8 +157,6 @@ class Feature:
162
157
  else:
163
158
  new_data = new_data.replace([-np.inf, np.inf], np.nan)
164
159
 
165
- new_data = new_data.rename(self.get_display_name())
166
-
167
160
  if is_root:
168
161
  self.data = new_data
169
162
  return new_data
@@ -333,65 +326,3 @@ class FeatureGroup:
333
326
  self.main_column_node.delete_data()
334
327
  for child in self.children:
335
328
  child.delete_data()
336
-
337
-
338
- class OperandGroup:
339
- def __init__(self, operand: MultiOperand, children: List[Union[Column, Feature]]):
340
- self.op = operand
341
- self.children = children
342
- self.data: Optional[pd.DataFrame] = None
343
-
344
- def get_columns(self, **kwargs) -> List[str]:
345
- column_list = []
346
- seen = set()
347
- for child in self.children:
348
- columns = child.get_columns(**kwargs)
349
- column_list.extend([f for f in columns if f not in seen])
350
- seen.update(columns)
351
- return column_list
352
-
353
- def get_display_names(self, **kwargs) -> List[str]:
354
- names = [Feature(op, self.children).get_display_name(**kwargs) for op in self.op.children]
355
- return names
356
-
357
- def calculate(self, data: pd.DataFrame, is_root=False) -> pd.DataFrame:
358
- if isinstance(self.op, PandasOperand):
359
- if self.op.is_vector:
360
- ds = [child.calculate(data) for child in self.children]
361
- new_data = self.op.calculate(data=ds)
362
- else:
363
- d1 = self.children[0].calculate(data)
364
- d2 = None if len(self.children) < 2 else self.children[1].calculate(data)
365
- new_data = self.op.calculate(data=d1, left=d1, right=d2)
366
-
367
- new_data = pd.DataFrame(new_data.values.tolist())
368
- new_data.columns = self.get_display_names()
369
- else:
370
- raise NotImplementedError(f"Unrecognized operator {self.op.name}.")
371
-
372
- if is_root:
373
- self.data = new_data
374
- return new_data
375
-
376
- @staticmethod
377
- def make_groups(candidates: List[Feature]) -> List[Union[Feature, "FeatureGroup"]]:
378
- grouped_features = []
379
-
380
- for _, features in sorted(
381
- map_reduce(
382
- candidates, lambda f: (f.op.common_type or "", ",".join([c.get_display_name() for c in f.children]))
383
- ).items(),
384
- key=operator.itemgetter(0),
385
- ):
386
- feature_list = list(features)
387
- multi_op = feature_list[0].op.make_multi_operand([f.op for f in feature_list])
388
- if multi_op is not None:
389
- grouped_features.append(OperandGroup(multi_op, feature_list[0].children))
390
- else:
391
- grouped_features.extend(feature_list)
392
- return grouped_features
393
-
394
- def delete_data(self):
395
- self.data = None
396
- for child in self.children:
397
- child.delete_data()
@@ -5,9 +5,6 @@ import pandas as pd
5
5
  import numpy as np
6
6
 
7
7
 
8
- MAIN_COLUMN = "main_column"
9
-
10
-
11
8
  class Operand(BaseModel):
12
9
  name: str
13
10
  alias: Optional[str]
@@ -21,7 +18,6 @@ class Operand(BaseModel):
21
18
  is_binary: bool = False
22
19
  is_vector: bool = False
23
20
  is_distribution_dependent: bool = False
24
- common_type: Optional[str] = None
25
21
  params: Optional[Dict[str, str]]
26
22
 
27
23
  def set_params(self, params: Dict[str, str]):
@@ -31,8 +27,8 @@ class Operand(BaseModel):
31
27
  def get_params(self) -> Dict[str, str]:
32
28
  return self.params
33
29
 
34
- def make_multi_operand(self, operands: List["Operand"]) -> Optional["MultiOperand"]:
35
- return None
30
+
31
+ MAIN_COLUMN = "main_column"
36
32
 
37
33
 
38
34
  class PandasOperand(Operand, abc.ABC):
@@ -86,7 +82,3 @@ class VectorizableMixin(Operand):
86
82
  value_columns = [col for col in input_columns if col != group_column]
87
83
 
88
84
  return group_column, value_columns
89
-
90
-
91
- class MultiOperand(Operand):
92
- children: List[Operand]
@@ -48,6 +48,7 @@ class DataSourcePublisher:
48
48
  data_table_uri: str,
49
49
  search_keys: Dict[str, SearchKey],
50
50
  update_frequency: str,
51
+ exclude_from_autofe_generation: Optional[List[str]],
51
52
  secondary_search_keys: Optional[Dict[str, SearchKey]] = None,
52
53
  sort_column: Optional[str] = None,
53
54
  date_format: Optional[str] = None,
@@ -57,7 +58,6 @@ class DataSourcePublisher:
57
58
  join_date_abs_limit_days: Optional[int] = None,
58
59
  features_for_embeddings: Optional[List[str]] = DEFAULT_GENERATE_EMBEDDINGS,
59
60
  data_table_id_to_replace: Optional[str] = None,
60
- exclude_from_autofe_generation: Optional[List[str]] = None,
61
61
  _force_generation=False,
62
62
  _silent=False,
63
63
  ) -> str:
@@ -17,6 +17,7 @@ from pandas.api.types import (
17
17
  is_numeric_dtype,
18
18
  is_period_dtype,
19
19
  is_string_dtype,
20
+ is_object_dtype,
20
21
  )
21
22
 
22
23
  from upgini.errors import ValidationError
@@ -219,7 +220,7 @@ class Dataset: # (pd.DataFrame):
219
220
  """Check that string values less than maximum characters for LLM"""
220
221
  # self.logger.info("Validate too long string values")
221
222
  for col in self.data.columns:
222
- if is_string_dtype(self.data[col]):
223
+ if is_string_dtype(self.data[col]) or is_object_dtype(self.data[col]):
223
224
  max_length: int = self.data[col].astype("str").str.len().max()
224
225
  if max_length > self.MAX_STRING_FEATURE_LENGTH:
225
226
  self.data[col] = self.data[col].astype("str").str.slice(stop=self.MAX_STRING_FEATURE_LENGTH)
@@ -350,7 +351,7 @@ class Dataset: # (pd.DataFrame):
350
351
  if postal_code is not None and postal_code in self.data.columns:
351
352
  # self.logger.info("Normalize postal code")
352
353
 
353
- if is_string_dtype(self.data[postal_code]):
354
+ if is_string_dtype(self.data[postal_code]) or is_object_dtype(self.data[postal_code]):
354
355
  try:
355
356
  self.data[postal_code] = self.data[postal_code].astype("float64").astype("Int64").astype("string")
356
357
  except Exception:
@@ -821,7 +822,7 @@ class Dataset: # (pd.DataFrame):
821
822
  return DataType.INT
822
823
  elif is_float_dtype(pandas_data_type):
823
824
  return DataType.DECIMAL
824
- elif is_string_dtype(pandas_data_type):
825
+ elif is_string_dtype(pandas_data_type) or is_object_dtype(pandas_data_type):
825
826
  return DataType.STRING
826
827
  else:
827
828
  msg = self.bundle.get("dataset_invalid_column_type").format(column_name, pandas_data_type)
@@ -1,4 +1,5 @@
1
1
  import dataclasses
2
+ import datetime
2
3
  import gc
3
4
  import hashlib
4
5
  import itertools
@@ -20,6 +21,7 @@ from pandas.api.types import (
20
21
  is_bool,
21
22
  is_datetime64_any_dtype,
22
23
  is_numeric_dtype,
24
+ is_object_dtype,
23
25
  is_period_dtype,
24
26
  is_string_dtype,
25
27
  )
@@ -146,6 +148,7 @@ class FeaturesEnricher(TransformerMixin):
146
148
  """
147
149
 
148
150
  TARGET_NAME = "target"
151
+ CURRENT_DATE = "current_date"
149
152
  RANDOM_STATE = 42
150
153
  CALCULATE_METRICS_THRESHOLD = 50_000_000
151
154
  CALCULATE_METRICS_MIN_THRESHOLD = 500
@@ -207,6 +210,7 @@ class FeaturesEnricher(TransformerMixin):
207
210
  client_ip: Optional[str] = None,
208
211
  client_visitorid: Optional[str] = None,
209
212
  custom_bundle_config: Optional[str] = None,
213
+ add_date_if_missing: bool = True,
210
214
  **kwargs,
211
215
  ):
212
216
  self.bundle = get_custom_bundle(custom_bundle_config)
@@ -317,6 +321,7 @@ class FeaturesEnricher(TransformerMixin):
317
321
  self.raise_validation_error = raise_validation_error
318
322
  self.exclude_columns = exclude_columns
319
323
  self.baseline_score_column = baseline_score_column
324
+ self.add_date_if_missing = add_date_if_missing
320
325
 
321
326
  def _get_api_key(self):
322
327
  return self._api_key
@@ -420,6 +425,9 @@ class FeaturesEnricher(TransformerMixin):
420
425
 
421
426
  self.__validate_search_keys(self.search_keys, self.search_id)
422
427
 
428
+ # Validate client estimator params
429
+ self._get_client_cat_features(estimator, X, self.search_keys)
430
+
423
431
  try:
424
432
  self.X = X
425
433
  self.y = y
@@ -813,6 +821,7 @@ class FeaturesEnricher(TransformerMixin):
813
821
  trace_id = trace_id or str(uuid.uuid4())
814
822
  start_time = time.time()
815
823
  with MDC(trace_id=trace_id):
824
+ self.logger.info("Start calculate metrics")
816
825
  if len(args) > 0:
817
826
  msg = f"WARNING: Unsupported positional arguments for calculate_metrics: {args}"
818
827
  self.logger.warning(msg)
@@ -864,22 +873,9 @@ class FeaturesEnricher(TransformerMixin):
864
873
  self.__display_support_link(msg)
865
874
  return None
866
875
 
867
- cat_features = None
868
- search_keys_for_metrics = []
869
- if (
870
- estimator is not None
871
- and hasattr(estimator, "get_param")
872
- and estimator.get_param("cat_features") is not None
873
- ):
874
- cat_features = estimator.get_param("cat_features")
875
- if len(cat_features) > 0 and isinstance(cat_features[0], int):
876
- cat_features = [effective_X.columns[i] for i in cat_features]
877
- for cat_feature in cat_features:
878
- if cat_feature in self.search_keys:
879
- if self.search_keys[cat_feature] in [SearchKey.COUNTRY, SearchKey.POSTAL_CODE]:
880
- search_keys_for_metrics.append(cat_feature)
881
- else:
882
- raise ValidationError(self.bundle.get("cat_feature_search_key").format(cat_feature))
876
+ cat_features, search_keys_for_metrics = self._get_client_cat_features(
877
+ estimator, effective_X, self.search_keys
878
+ )
883
879
 
884
880
  prepared_data = self._prepare_data_for_metrics(
885
881
  trace_id=trace_id,
@@ -894,6 +890,7 @@ class FeaturesEnricher(TransformerMixin):
894
890
  search_keys_for_metrics=search_keys_for_metrics,
895
891
  progress_bar=progress_bar,
896
892
  progress_callback=progress_callback,
893
+ cat_features=cat_features,
897
894
  )
898
895
  if prepared_data is None:
899
896
  return None
@@ -1269,6 +1266,29 @@ class FeaturesEnricher(TransformerMixin):
1269
1266
 
1270
1267
  return _cv, groups
1271
1268
 
1269
+ def _get_client_cat_features(
1270
+ self, estimator: Optional[Any], X: pd.DataFrame, search_keys: Dict[str, SearchKey]
1271
+ ) -> Optional[List[str]]:
1272
+ cat_features = None
1273
+ search_keys_for_metrics = []
1274
+ if (
1275
+ estimator is not None
1276
+ and hasattr(estimator, "get_param")
1277
+ and estimator.get_param("cat_features") is not None
1278
+ ):
1279
+ cat_features = estimator.get_param("cat_features")
1280
+ if len(cat_features) > 0:
1281
+ if all([isinstance(f, int) for f in cat_features]):
1282
+ cat_features = [X.columns[i] for i in cat_features]
1283
+ self.logger.info(f"Collected categorical features {cat_features} from user estimator")
1284
+ for cat_feature in cat_features:
1285
+ if cat_feature in search_keys:
1286
+ if search_keys[cat_feature] in [SearchKey.COUNTRY, SearchKey.POSTAL_CODE]:
1287
+ search_keys_for_metrics.append(cat_feature)
1288
+ else:
1289
+ raise ValidationError(self.bundle.get("cat_feature_search_key").format(cat_feature))
1290
+ return cat_features, search_keys_for_metrics
1291
+
1272
1292
  def _prepare_data_for_metrics(
1273
1293
  self,
1274
1294
  trace_id: str,
@@ -1283,6 +1303,7 @@ class FeaturesEnricher(TransformerMixin):
1283
1303
  search_keys_for_metrics: Optional[List[str]] = None,
1284
1304
  progress_bar: Optional[ProgressBar] = None,
1285
1305
  progress_callback: Optional[Callable[[SearchProgress], Any]] = None,
1306
+ cat_features: Optional[List[str]] = None,
1286
1307
  ):
1287
1308
  is_input_same_as_fit, X, y, eval_set = self._is_input_same_as_fit(X, y, eval_set)
1288
1309
  is_demo_dataset = hash_input(X, y, eval_set) in DEMO_DATASET_HASHES
@@ -1340,9 +1361,8 @@ class FeaturesEnricher(TransformerMixin):
1340
1361
 
1341
1362
  # Detect and drop high cardinality columns in train
1342
1363
  columns_with_high_cardinality = FeaturesValidator.find_high_cardinality(fitting_X)
1343
- columns_with_high_cardinality = [
1344
- c for c in columns_with_high_cardinality if c not in (self.generate_features or [])
1345
- ]
1364
+ non_excluding_columns = (self.generate_features or []) + (cat_features or [])
1365
+ columns_with_high_cardinality = [c for c in columns_with_high_cardinality if c not in non_excluding_columns]
1346
1366
  if len(columns_with_high_cardinality) > 0:
1347
1367
  self.logger.warning(
1348
1368
  f"High cardinality columns {columns_with_high_cardinality} will be dropped for metrics calculation"
@@ -1804,10 +1824,11 @@ class FeaturesEnricher(TransformerMixin):
1804
1824
  else:
1805
1825
  features_section = ""
1806
1826
 
1807
- api_example = f"""curl 'https://inference-upgini.azurewebsites.net/api/http_inference_trigger' \\
1827
+ search_id = self._search_task.search_task_id
1828
+ api_example = f"""curl 'https://search.upgini.com/online/api/http_inference_trigger?search_id={search_id}' \\
1808
1829
  -H 'Authorization: {self.api_key}' \\
1809
1830
  -H 'Content-Type: application/json' \\
1810
- -d '{{"search_id": "{self._search_task.search_task_id}", "search_keys": {keys}{features_section}}}'"""
1831
+ -d '{{"search_keys": {keys}{features_section}}}'"""
1811
1832
  return api_example
1812
1833
 
1813
1834
  def _get_copy_of_runtime_parameters(self) -> RuntimeParameters:
@@ -1902,6 +1923,8 @@ class FeaturesEnricher(TransformerMixin):
1902
1923
  generated_features.extend(converter.generated_features)
1903
1924
  else:
1904
1925
  self.logger.info("Input dataset hasn't date column")
1926
+ if self.add_date_if_missing:
1927
+ df = self._add_current_date_as_key(df, search_keys, self.logger, self.bundle)
1905
1928
  email_column = self._get_email_column(search_keys)
1906
1929
  hem_column = self._get_hem_column(search_keys)
1907
1930
  email_converted_to_hem = False
@@ -2220,9 +2243,7 @@ class FeaturesEnricher(TransformerMixin):
2220
2243
  self.fit_search_keys = self.search_keys.copy()
2221
2244
  self.fit_search_keys = self.__prepare_search_keys(validated_X, self.fit_search_keys, is_demo_dataset)
2222
2245
 
2223
- validate_dates_distribution(
2224
- validated_X, self.fit_search_keys, self.logger, self.bundle, self.warning_counter
2225
- )
2246
+ validate_dates_distribution(validated_X, self.fit_search_keys, self.logger, self.bundle, self.warning_counter)
2226
2247
 
2227
2248
  maybe_date_column = self._get_date_column(self.fit_search_keys)
2228
2249
  has_date = maybe_date_column is not None
@@ -2273,6 +2294,8 @@ class FeaturesEnricher(TransformerMixin):
2273
2294
  self.fit_generated_features.extend(converter.generated_features)
2274
2295
  else:
2275
2296
  self.logger.info("Input dataset hasn't date column")
2297
+ if self.add_date_if_missing:
2298
+ df = self._add_current_date_as_key(df, self.fit_search_keys, self.logger, self.bundle)
2276
2299
  email_column = self._get_email_column(self.fit_search_keys)
2277
2300
  hem_column = self._get_hem_column(self.fit_search_keys)
2278
2301
  email_converted_to_hem = False
@@ -2853,6 +2876,25 @@ class FeaturesEnricher(TransformerMixin):
2853
2876
  if t in [SearchKey.DATE, SearchKey.DATETIME]:
2854
2877
  return col
2855
2878
 
2879
+ @staticmethod
2880
+ def _add_current_date_as_key(
2881
+ df: pd.DataFrame, search_keys: Dict[str, SearchKey], logger: logging.Logger, bundle: ResourceBundle
2882
+ ) -> pd.DataFrame:
2883
+ if (
2884
+ set(search_keys.values()) == {SearchKey.PHONE}
2885
+ or set(search_keys.values()) == {SearchKey.EMAIL}
2886
+ or set(search_keys.values()) == {SearchKey.HEM}
2887
+ or set(search_keys.values()) == {SearchKey.COUNTRY, SearchKey.POSTAL_CODE}
2888
+ ):
2889
+ msg = bundle.get("current_date_added")
2890
+ print(msg)
2891
+ logger.warning(msg)
2892
+ df[FeaturesEnricher.CURRENT_DATE] = datetime.date.today()
2893
+ search_keys[FeaturesEnricher.CURRENT_DATE] = SearchKey.DATE
2894
+ converter = DateTimeSearchKeyConverter(FeaturesEnricher.CURRENT_DATE, None, logger, bundle)
2895
+ df = converter.convert(df)
2896
+ return df
2897
+
2856
2898
  @staticmethod
2857
2899
  def _get_group_columns(df: pd.DataFrame, search_keys: Dict[str, SearchKey]) -> List[str]:
2858
2900
  return [
@@ -2903,9 +2945,7 @@ class FeaturesEnricher(TransformerMixin):
2903
2945
  [
2904
2946
  c
2905
2947
  for c in df.columns
2906
- if c not in sort_columns
2907
- and c not in sort_exclude_columns
2908
- and df[c].nunique() > 1
2948
+ if c not in sort_columns and c not in sort_exclude_columns and df[c].nunique() > 1
2909
2949
  ]
2910
2950
  # [
2911
2951
  # sk
@@ -2943,7 +2983,7 @@ class FeaturesEnricher(TransformerMixin):
2943
2983
 
2944
2984
  def __correct_target(self, df: pd.DataFrame) -> pd.DataFrame:
2945
2985
  target = df[self.TARGET_NAME]
2946
- if is_string_dtype(target):
2986
+ if is_string_dtype(target) or is_object_dtype(target):
2947
2987
  maybe_numeric_target = pd.to_numeric(target, errors="coerce")
2948
2988
  # If less than 5% is non numeric then leave this rows with NaN target and later it will be dropped
2949
2989
  if maybe_numeric_target.isna().sum() <= _num_samples(df) * 0.05:
@@ -3343,7 +3383,8 @@ class FeaturesEnricher(TransformerMixin):
3343
3383
  valid_search_keys[column_name] = SearchKey.CUSTOM_KEY
3344
3384
  else:
3345
3385
  if x[column_name].isnull().all() or (
3346
- is_string_dtype(x[column_name]) and (x[column_name].astype("string").str.strip() == "").all()
3386
+ (is_string_dtype(x[column_name]) or is_object_dtype(x[column_name]))
3387
+ and (x[column_name].astype("string").str.strip() == "").all()
3347
3388
  ):
3348
3389
  raise ValidationError(self.bundle.get("empty_search_key").format(column_name))
3349
3390
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * FingerprintJS v3.4.2 - Copyright (c) FingerprintJS, Inc, 2023 (https://fingerprint.com)
3
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
4
+ *
5
+ * This software contains code from open-source projects:
6
+ * MurmurHash3 by Karan Lyons (https://github.com/karanlyons/murmurHash3.js)
7
+ */
8
+ var e=function(){return e=Object.assign||function(e){for(var n,t=1,r=arguments.length;t<r;t++)for(var o in n=arguments[t])Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o]);return e},e.apply(this,arguments)};function n(e,n,t,r){return new(t||(t=Promise))((function(o,a){function i(e){try{u(r.next(e))}catch(n){a(n)}}function c(e){try{u(r.throw(e))}catch(n){a(n)}}function u(e){var n;e.done?o(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(i,c)}u((r=r.apply(e,n||[])).next())}))}function t(e,n){var t,r,o,a,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return a={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(a[Symbol.iterator]=function(){return this}),a;function c(c){return function(u){return function(c){if(t)throw new TypeError("Generator is already executing.");for(;a&&(a=0,c[0]&&(i=0)),i;)try{if(t=1,r&&(o=2&c[0]?r.return:c[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,c[1])).done)return o;switch(r=0,o&&(c=[2&c[0],o.value]),c[0]){case 0:case 1:o=c;break;case 4:return i.label++,{value:c[1],done:!1};case 5:i.label++,r=c[1],c=[0];continue;case 7:c=i.ops.pop(),i.trys.pop();continue;default:if(!(o=i.trys,(o=o.length>0&&o[o.length-1])||6!==c[0]&&2!==c[0])){i=0;continue}if(3===c[0]&&(!o||c[1]>o[0]&&c[1]<o[3])){i.label=c[1];break}if(6===c[0]&&i.label<o[1]){i.label=o[1],o=c;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(c);break}o[2]&&i.ops.pop(),i.trys.pop();continue}c=n.call(e,i)}catch(u){c=[6,u],r=0}finally{t=o=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}([c,u])}}}function r(e,n,t){if(t||2===arguments.length)for(var r,o=0,a=n.length;o<a;o++)!r&&o in n||(r||(r=Array.prototype.slice.call(n,0,o)),r[o]=n[o]);return e.concat(r||Array.prototype.slice.call(n))}function o(e,n){return new Promise((function(t){return setTimeout(t,e,n)}))}function a(e){return!!e&&"function"==typeof e.then}function i(e,n){try{var t=e();a(t)?t.then((function(e){return n(!0,e)}),(function(e){return n(!1,e)})):n(!0,t)}catch(r){n(!1,r)}}function c(e,r,a){return void 0===a&&(a=16),n(this,void 0,void 0,(function(){var n,i,c,u;return t(this,(function(t){switch(t.label){case 0:n=Array(e.length),i=Date.now(),c=0,t.label=1;case 1:return c<e.length?(n[c]=r(e[c],c),(u=Date.now())>=i+a?(i=u,[4,o(0)]):[3,3]):[3,4];case 2:t.sent(),t.label=3;case 3:return++c,[3,1];case 4:return[2,n]}}))}))}function u(e){e.then(void 0,(function(){}))}function l(e,n){e=[e[0]>>>16,65535&e[0],e[1]>>>16,65535&e[1]],n=[n[0]>>>16,65535&n[0],n[1]>>>16,65535&n[1]];var t=[0,0,0,0];return t[3]+=e[3]+n[3],t[2]+=t[3]>>>16,t[3]&=65535,t[2]+=e[2]+n[2],t[1]+=t[2]>>>16,t[2]&=65535,t[1]+=e[1]+n[1],t[0]+=t[1]>>>16,t[1]&=65535,t[0]+=e[0]+n[0],t[0]&=65535,[t[0]<<16|t[1],t[2]<<16|t[3]]}function s(e,n){e=[e[0]>>>16,65535&e[0],e[1]>>>16,65535&e[1]],n=[n[0]>>>16,65535&n[0],n[1]>>>16,65535&n[1]];var t=[0,0,0,0];return t[3]+=e[3]*n[3],t[2]+=t[3]>>>16,t[3]&=65535,t[2]+=e[2]*n[3],t[1]+=t[2]>>>16,t[2]&=65535,t[2]+=e[3]*n[2],t[1]+=t[2]>>>16,t[2]&=65535,t[1]+=e[1]*n[3],t[0]+=t[1]>>>16,t[1]&=65535,t[1]+=e[2]*n[2],t[0]+=t[1]>>>16,t[1]&=65535,t[1]+=e[3]*n[1],t[0]+=t[1]>>>16,t[1]&=65535,t[0]+=e[0]*n[3]+e[1]*n[2]+e[2]*n[1]+e[3]*n[0],t[0]&=65535,[t[0]<<16|t[1],t[2]<<16|t[3]]}function d(e,n){return 32===(n%=64)?[e[1],e[0]]:n<32?[e[0]<<n|e[1]>>>32-n,e[1]<<n|e[0]>>>32-n]:(n-=32,[e[1]<<n|e[0]>>>32-n,e[0]<<n|e[1]>>>32-n])}function m(e,n){return 0===(n%=64)?e:n<32?[e[0]<<n|e[1]>>>32-n,e[1]<<n]:[e[1]<<n-32,0]}function f(e,n){return[e[0]^n[0],e[1]^n[1]]}function v(e){return e=f(e,[0,e[0]>>>1]),e=f(e=s(e,[4283543511,3981806797]),[0,e[0]>>>1]),e=f(e=s(e,[3301882366,444984403]),[0,e[0]>>>1])}function h(e,n){n=n||0;var t,r=(e=e||"").length%16,o=e.length-r,a=[0,n],i=[0,n],c=[0,0],u=[0,0],h=[2277735313,289559509],p=[1291169091,658871167];for(t=0;t<o;t+=16)c=[255&e.charCodeAt(t+4)|(255&e.charCodeAt(t+5))<<8|(255&e.charCodeAt(t+6))<<16|(255&e.charCodeAt(t+7))<<24,255&e.charCodeAt(t)|(255&e.charCodeAt(t+1))<<8|(255&e.charCodeAt(t+2))<<16|(255&e.charCodeAt(t+3))<<24],u=[255&e.charCodeAt(t+12)|(255&e.charCodeAt(t+13))<<8|(255&e.charCodeAt(t+14))<<16|(255&e.charCodeAt(t+15))<<24,255&e.charCodeAt(t+8)|(255&e.charCodeAt(t+9))<<8|(255&e.charCodeAt(t+10))<<16|(255&e.charCodeAt(t+11))<<24],c=d(c=s(c,h),31),a=l(a=d(a=f(a,c=s(c,p)),27),i),a=l(s(a,[0,5]),[0,1390208809]),u=d(u=s(u,p),33),i=l(i=d(i=f(i,u=s(u,h)),31),a),i=l(s(i,[0,5]),[0,944331445]);switch(c=[0,0],u=[0,0],r){case 15:u=f(u,m([0,e.charCodeAt(t+14)],48));case 14:u=f(u,m([0,e.charCodeAt(t+13)],40));case 13:u=f(u,m([0,e.charCodeAt(t+12)],32));case 12:u=f(u,m([0,e.charCodeAt(t+11)],24));case 11:u=f(u,m([0,e.charCodeAt(t+10)],16));case 10:u=f(u,m([0,e.charCodeAt(t+9)],8));case 9:u=s(u=f(u,[0,e.charCodeAt(t+8)]),p),i=f(i,u=s(u=d(u,33),h));case 8:c=f(c,m([0,e.charCodeAt(t+7)],56));case 7:c=f(c,m([0,e.charCodeAt(t+6)],48));case 6:c=f(c,m([0,e.charCodeAt(t+5)],40));case 5:c=f(c,m([0,e.charCodeAt(t+4)],32));case 4:c=f(c,m([0,e.charCodeAt(t+3)],24));case 3:c=f(c,m([0,e.charCodeAt(t+2)],16));case 2:c=f(c,m([0,e.charCodeAt(t+1)],8));case 1:c=s(c=f(c,[0,e.charCodeAt(t)]),h),a=f(a,c=s(c=d(c,31),p))}return a=l(a=f(a,[0,e.length]),i=f(i,[0,e.length])),i=l(i,a),a=l(a=v(a),i=v(i)),i=l(i,a),("00000000"+(a[0]>>>0).toString(16)).slice(-8)+("00000000"+(a[1]>>>0).toString(16)).slice(-8)+("00000000"+(i[0]>>>0).toString(16)).slice(-8)+("00000000"+(i[1]>>>0).toString(16)).slice(-8)}function p(e){return parseInt(e)}function b(e){return parseFloat(e)}function y(e,n){return"number"==typeof e&&isNaN(e)?n:e}function g(e){return e.reduce((function(e,n){return e+(n?1:0)}),0)}function w(e,n){if(void 0===n&&(n=1),Math.abs(n)>=1)return Math.round(e/n)*n;var t=1/n;return Math.round(e*t)/t}function L(e){return e&&"object"==typeof e&&"message"in e?e:{message:e}}function k(e){return"function"!=typeof e}function V(e,r,o){var a=Object.keys(e).filter((function(e){return!function(e,n){for(var t=0,r=e.length;t<r;++t)if(e[t]===n)return!0;return!1}(o,e)})),l=c(a,(function(n){return function(e,n){var t=new Promise((function(t){var r=Date.now();i(e.bind(null,n),(function(){for(var e=[],n=0;n<arguments.length;n++)e[n]=arguments[n];var o=Date.now()-r;if(!e[0])return t((function(){return{error:L(e[1]),duration:o}}));var a=e[1];if(k(a))return t((function(){return{value:a,duration:o}}));t((function(){return new Promise((function(e){var n=Date.now();i(a,(function(){for(var t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];var a=o+Date.now()-n;if(!t[0])return e({error:L(t[1]),duration:a});e({value:t[1],duration:a})}))}))}))}))}));return u(t),function(){return t.then((function(e){return e()}))}}(e[n],r)}));return u(l),function(){return n(this,void 0,void 0,(function(){var e,n,r,o;return t(this,(function(t){switch(t.label){case 0:return[4,l];case 1:return[4,c(t.sent(),(function(e){var n=e();return u(n),n}))];case 2:return e=t.sent(),[4,Promise.all(e)];case 3:for(n=t.sent(),r={},o=0;o<a.length;++o)r[a[o]]=n[o];return[2,r]}}))}))}}function Z(e,n){var t=function(e){return k(e)?n(e):function(){var t=e();return a(t)?t.then(n):n(t)}};return function(n){var r=e(n);return a(r)?r.then(t):t(r)}}function W(){var e=window,n=navigator;return g(["MSCSSMatrix"in e,"msSetImmediate"in e,"msIndexedDB"in e,"msMaxTouchPoints"in n,"msPointerEnabled"in n])>=4}function C(){var e=window,n=navigator;return g(["msWriteProfilerMark"in e,"MSStream"in e,"msLaunchUri"in n,"msSaveBlob"in n])>=3&&!W()}function S(){var e=window,n=navigator;return g(["webkitPersistentStorage"in n,"webkitTemporaryStorage"in n,0===n.vendor.indexOf("Google"),"webkitResolveLocalFileSystemURL"in e,"BatteryManager"in e,"webkitMediaStream"in e,"webkitSpeechGrammar"in e])>=5}function x(){var e=window,n=navigator;return g(["ApplePayError"in e,"CSSPrimitiveValue"in e,"Counter"in e,0===n.vendor.indexOf("Apple"),"getStorageUpdates"in n,"WebKitMediaKeys"in e])>=4}function F(){var e=window;return g(["safari"in e,!("DeviceMotionEvent"in e),!("ongestureend"in e),!("standalone"in navigator)])>=3}function Y(){var e,n,t=window;return g(["buildID"in navigator,"MozAppearance"in(null!==(n=null===(e=document.documentElement)||void 0===e?void 0:e.style)&&void 0!==n?n:{}),"onmozfullscreenchange"in t,"mozInnerScreenX"in t,"CSSMozDocumentRule"in t,"CanvasCaptureMediaStream"in t])>=4}function M(){var e=document;return e.fullscreenElement||e.msFullscreenElement||e.mozFullScreenElement||e.webkitFullscreenElement||null}function G(){var e=S(),n=Y();if(!e&&!n)return!1;var t=window;return g(["onorientationchange"in t,"orientation"in t,e&&!("SharedWorker"in t),n&&/android/i.test(navigator.appVersion)])>=2}function R(e){var n=new Error(e);return n.name=e,n}function X(e,r,a){var i,c,u;return void 0===a&&(a=50),n(this,void 0,void 0,(function(){var n,l;return t(this,(function(t){switch(t.label){case 0:n=document,t.label=1;case 1:return n.body?[3,3]:[4,o(a)];case 2:return t.sent(),[3,1];case 3:l=n.createElement("iframe"),t.label=4;case 4:return t.trys.push([4,,10,11]),[4,new Promise((function(e,t){var o=!1,a=function(){o=!0,e()};l.onload=a,l.onerror=function(e){o=!0,t(e)};var i=l.style;i.setProperty("display","block","important"),i.position="absolute",i.top="0",i.left="0",i.visibility="hidden",r&&"srcdoc"in l?l.srcdoc=r:l.src="about:blank",n.body.appendChild(l);var c=function(){var e,n;o||("complete"===(null===(n=null===(e=l.contentWindow)||void 0===e?void 0:e.document)||void 0===n?void 0:n.readyState)?a():setTimeout(c,10))};c()}))];case 5:t.sent(),t.label=6;case 6:return(null===(c=null===(i=l.contentWindow)||void 0===i?void 0:i.document)||void 0===c?void 0:c.body)?[3,8]:[4,o(a)];case 7:return t.sent(),[3,6];case 8:return[4,e(l,l.contentWindow)];case 9:return[2,t.sent()];case 10:return null===(u=l.parentNode)||void 0===u||u.removeChild(l),[7];case 11:return[2]}}))}))}function A(e){for(var n=function(e){for(var n,t,r="Unexpected syntax '".concat(e,"'"),o=/^\s*([a-z-]*)(.*)$/i.exec(e),a=o[1]||void 0,i={},c=/([.:#][\w-]+|\[.+?\])/gi,u=function(e,n){i[e]=i[e]||[],i[e].push(n)};;){var l=c.exec(o[2]);if(!l)break;var s=l[0];switch(s[0]){case".":u("class",s.slice(1));break;case"#":u("id",s.slice(1));break;case"[":var d=/^\[([\w-]+)([~|^$*]?=("(.*?)"|([\w-]+)))?(\s+[is])?\]$/.exec(s);if(!d)throw new Error(r);u(d[1],null!==(t=null!==(n=d[4])&&void 0!==n?n:d[5])&&void 0!==t?t:"");break;default:throw new Error(r)}}return[a,i]}(e),t=n[0],r=n[1],o=document.createElement(null!=t?t:"div"),a=0,i=Object.keys(r);a<i.length;a++){var c=i[a],u=r[c].join(" ");"style"===c?j(o.style,u):o.setAttribute(c,u)}return o}function j(e,n){for(var t=0,r=n.split(";");t<r.length;t++){var o=r[t],a=/^\s*([\w-]+)\s*:\s*(.+?)(\s*!([\w-]+))?\s*$/.exec(o);if(a){var i=a[1],c=a[2],u=a[4];e.setProperty(i,c,u||"")}}}var I=["monospace","sans-serif","serif"],J=["sans-serif-thin","ARNO PRO","Agency FB","Arabic Typesetting","Arial Unicode MS","AvantGarde Bk BT","BankGothic Md BT","Batang","Bitstream Vera Sans Mono","Calibri","Century","Century Gothic","Clarendon","EUROSTILE","Franklin Gothic","Futura Bk BT","Futura Md BT","GOTHAM","Gill Sans","HELV","Haettenschweiler","Helvetica Neue","Humanst521 BT","Leelawadee","Letter Gothic","Levenim MT","Lucida Bright","Lucida Sans","Menlo","MS Mincho","MS Outlook","MS Reference Specialty","MS UI Gothic","MT Extra","MYRIAD PRO","Marlett","Meiryo UI","Microsoft Uighur","Minion Pro","Monotype Corsiva","PMingLiU","Pristina","SCRIPTINA","Segoe UI Light","Serifa","SimHei","Small Fonts","Staccato222 BT","TRAJAN PRO","Univers CE 55 Medium","Vrinda","ZWAdobeF"];function H(e){return e.toDataURL()}var P,N;function z(){var e=this;return function(){if(void 0===N){var e=function(){var n=D();E(n)?N=setTimeout(e,2500):(P=n,N=void 0)};e()}}(),function(){return n(e,void 0,void 0,(function(){var e;return t(this,(function(n){switch(n.label){case 0:return E(e=D())?P?[2,r([],P,!0)]:M()?[4,(t=document,(t.exitFullscreen||t.msExitFullscreen||t.mozCancelFullScreen||t.webkitExitFullscreen).call(t))]:[3,2]:[3,2];case 1:n.sent(),e=D(),n.label=2;case 2:return E(e)||(P=e),[2,e]}var t}))}))}}function D(){var e=screen;return[y(b(e.availTop),null),y(b(e.width)-b(e.availWidth)-y(b(e.availLeft),0),null),y(b(e.height)-b(e.availHeight)-y(b(e.availTop),0),null),y(b(e.availLeft),null)]}function E(e){for(var n=0;n<4;++n)if(e[n])return!1;return!0}function T(e){var r;return n(this,void 0,void 0,(function(){var n,a,i,c,u,l,s;return t(this,(function(t){switch(t.label){case 0:for(n=document,a=n.createElement("div"),i=new Array(e.length),c={},B(a),s=0;s<e.length;++s)"DIALOG"===(u=A(e[s])).tagName&&u.show(),B(l=n.createElement("div")),l.appendChild(u),a.appendChild(l),i[s]=u;t.label=1;case 1:return n.body?[3,3]:[4,o(50)];case 2:return t.sent(),[3,1];case 3:n.body.appendChild(a);try{for(s=0;s<e.length;++s)i[s].offsetParent||(c[e[s]]=!0)}finally{null===(r=a.parentNode)||void 0===r||r.removeChild(a)}return[2,c]}}))}))}function B(e){e.style.setProperty("display","block","important")}function _(e){return matchMedia("(inverted-colors: ".concat(e,")")).matches}function O(e){return matchMedia("(forced-colors: ".concat(e,")")).matches}function U(e){return matchMedia("(prefers-contrast: ".concat(e,")")).matches}function Q(e){return matchMedia("(prefers-reduced-motion: ".concat(e,")")).matches}function K(e){return matchMedia("(dynamic-range: ".concat(e,")")).matches}var q=Math,$=function(){return 0};var ee={default:[],apple:[{font:"-apple-system-body"}],serif:[{fontFamily:"serif"}],sans:[{fontFamily:"sans-serif"}],mono:[{fontFamily:"monospace"}],min:[{fontSize:"1px"}],system:[{fontFamily:"system-ui"}]};var ne={fonts:function(){return X((function(e,n){var t=n.document,r=t.body;r.style.fontSize="48px";var o=t.createElement("div"),a={},i={},c=function(e){var n=t.createElement("span"),r=n.style;return r.position="absolute",r.top="0",r.left="0",r.fontFamily=e,n.textContent="mmMwWLliI0O&1",o.appendChild(n),n},u=I.map(c),l=function(){for(var e={},n=function(n){e[n]=I.map((function(e){return function(e,n){return c("'".concat(e,"',").concat(n))}(n,e)}))},t=0,r=J;t<r.length;t++){n(r[t])}return e}();r.appendChild(o);for(var s=0;s<I.length;s++)a[I[s]]=u[s].offsetWidth,i[I[s]]=u[s].offsetHeight;return J.filter((function(e){return n=l[e],I.some((function(e,t){return n[t].offsetWidth!==a[e]||n[t].offsetHeight!==i[e]}));var n}))}))},domBlockers:function(e){var r=(void 0===e?{}:e).debug;return n(this,void 0,void 0,(function(){var e,n,o,a,i;return t(this,(function(t){switch(t.label){case 0:return x()||G()?(c=atob,e={abpIndo:["#Iklan-Melayang","#Kolom-Iklan-728","#SidebarIklan-wrapper",'[title="ALIENBOLA" i]',c("I0JveC1CYW5uZXItYWRz")],abpvn:[".quangcao","#mobileCatfish",c("LmNsb3NlLWFkcw=="),'[id^="bn_bottom_fixed_"]',"#pmadv"],adBlockFinland:[".mainostila",c("LnNwb25zb3JpdA=="),".ylamainos",c("YVtocmVmKj0iL2NsaWNrdGhyZ2guYXNwPyJd"),c("YVtocmVmXj0iaHR0cHM6Ly9hcHAucmVhZHBlYWsuY29tL2FkcyJd")],adBlockPersian:["#navbar_notice_50",".kadr",'TABLE[width="140px"]',"#divAgahi",c("YVtocmVmXj0iaHR0cDovL2cxLnYuZndtcm0ubmV0L2FkLyJd")],adBlockWarningRemoval:["#adblock-honeypot",".adblocker-root",".wp_adblock_detect",c("LmhlYWRlci1ibG9ja2VkLWFk"),c("I2FkX2Jsb2NrZXI=")],adGuardAnnoyances:[".hs-sosyal","#cookieconsentdiv",'div[class^="app_gdpr"]',".as-oil",'[data-cypress="soft-push-notification-modal"]'],adGuardBase:[".BetterJsPopOverlay",c("I2FkXzMwMFgyNTA="),c("I2Jhbm5lcmZsb2F0MjI="),c("I2NhbXBhaWduLWJhbm5lcg=="),c("I0FkLUNvbnRlbnQ=")],adGuardChinese:[c("LlppX2FkX2FfSA=="),c("YVtocmVmKj0iLmh0aGJldDM0LmNvbSJd"),"#widget-quan",c("YVtocmVmKj0iLzg0OTkyMDIwLnh5eiJd"),c("YVtocmVmKj0iLjE5NTZobC5jb20vIl0=")],adGuardFrench:["#pavePub",c("LmFkLWRlc2t0b3AtcmVjdGFuZ2xl"),".mobile_adhesion",".widgetadv",c("LmFkc19iYW4=")],adGuardGerman:['aside[data-portal-id="leaderboard"]'],adGuardJapanese:["#kauli_yad_1",c("YVtocmVmXj0iaHR0cDovL2FkMi50cmFmZmljZ2F0ZS5uZXQvIl0="),c("Ll9wb3BJbl9pbmZpbml0ZV9hZA=="),c("LmFkZ29vZ2xl"),c("Ll9faXNib29zdFJldHVybkFk")],adGuardMobile:[c("YW1wLWF1dG8tYWRz"),c("LmFtcF9hZA=="),'amp-embed[type="24smi"]',"#mgid_iframe1",c("I2FkX2ludmlld19hcmVh")],adGuardRussian:[c("YVtocmVmXj0iaHR0cHM6Ly9hZC5sZXRtZWFkcy5jb20vIl0="),c("LnJlY2xhbWE="),'div[id^="smi2adblock"]',c("ZGl2W2lkXj0iQWRGb3hfYmFubmVyXyJd"),"#psyduckpockeball"],adGuardSocial:[c("YVtocmVmXj0iLy93d3cuc3R1bWJsZXVwb24uY29tL3N1Ym1pdD91cmw9Il0="),c("YVtocmVmXj0iLy90ZWxlZ3JhbS5tZS9zaGFyZS91cmw/Il0="),".etsy-tweet","#inlineShare",".popup-social"],adGuardSpanishPortuguese:["#barraPublicidade","#Publicidade","#publiEspecial","#queTooltip",".cnt-publi"],adGuardTrackingProtection:["#qoo-counter",c("YVtocmVmXj0iaHR0cDovL2NsaWNrLmhvdGxvZy5ydS8iXQ=="),c("YVtocmVmXj0iaHR0cDovL2hpdGNvdW50ZXIucnUvdG9wL3N0YXQucGhwIl0="),c("YVtocmVmXj0iaHR0cDovL3RvcC5tYWlsLnJ1L2p1bXAiXQ=="),"#top100counter"],adGuardTurkish:["#backkapat",c("I3Jla2xhbWk="),c("YVtocmVmXj0iaHR0cDovL2Fkc2Vydi5vbnRlay5jb20udHIvIl0="),c("YVtocmVmXj0iaHR0cDovL2l6bGVuemkuY29tL2NhbXBhaWduLyJd"),c("YVtocmVmXj0iaHR0cDovL3d3dy5pbnN0YWxsYWRzLm5ldC8iXQ==")],bulgarian:[c("dGQjZnJlZW5ldF90YWJsZV9hZHM="),"#ea_intext_div",".lapni-pop-over","#xenium_hot_offers"],easyList:[".yb-floorad",c("LndpZGdldF9wb19hZHNfd2lkZ2V0"),c("LnRyYWZmaWNqdW5reS1hZA=="),".textad_headline",c("LnNwb25zb3JlZC10ZXh0LWxpbmtz")],easyListChina:[c("LmFwcGd1aWRlLXdyYXBbb25jbGljayo9ImJjZWJvcy5jb20iXQ=="),c("LmZyb250cGFnZUFkdk0="),"#taotaole","#aafoot.top_box",".cfa_popup"],easyListCookie:[".ezmob-footer",".cc-CookieWarning","[data-cookie-number]",c("LmF3LWNvb2tpZS1iYW5uZXI="),".sygnal24-gdpr-modal-wrap"],easyListCzechSlovak:["#onlajny-stickers",c("I3Jla2xhbW5pLWJveA=="),c("LnJla2xhbWEtbWVnYWJvYXJk"),".sklik",c("W2lkXj0ic2tsaWtSZWtsYW1hIl0=")],easyListDutch:[c("I2FkdmVydGVudGll"),c("I3ZpcEFkbWFya3RCYW5uZXJCbG9jaw=="),".adstekst",c("YVtocmVmXj0iaHR0cHM6Ly94bHR1YmUubmwvY2xpY2svIl0="),"#semilo-lrectangle"],easyListGermany:["#SSpotIMPopSlider",c("LnNwb25zb3JsaW5rZ3J1ZW4="),c("I3dlcmJ1bmdza3k="),c("I3Jla2xhbWUtcmVjaHRzLW1pdHRl"),c("YVtocmVmXj0iaHR0cHM6Ly9iZDc0Mi5jb20vIl0=")],easyListItaly:[c("LmJveF9hZHZfYW5udW5jaQ=="),".sb-box-pubbliredazionale",c("YVtocmVmXj0iaHR0cDovL2FmZmlsaWF6aW9uaWFkcy5zbmFpLml0LyJd"),c("YVtocmVmXj0iaHR0cHM6Ly9hZHNlcnZlci5odG1sLml0LyJd"),c("YVtocmVmXj0iaHR0cHM6Ly9hZmZpbGlhemlvbmlhZHMuc25haS5pdC8iXQ==")],easyListLithuania:[c("LnJla2xhbW9zX3RhcnBhcw=="),c("LnJla2xhbW9zX251b3JvZG9z"),c("aW1nW2FsdD0iUmVrbGFtaW5pcyBza3lkZWxpcyJd"),c("aW1nW2FsdD0iRGVkaWt1b3RpLmx0IHNlcnZlcmlhaSJd"),c("aW1nW2FsdD0iSG9zdGluZ2FzIFNlcnZlcmlhaS5sdCJd")],estonian:[c("QVtocmVmKj0iaHR0cDovL3BheTRyZXN1bHRzMjQuZXUiXQ==")],fanboyAnnoyances:["#ac-lre-player",".navigate-to-top","#subscribe_popup",".newsletter_holder","#back-top"],fanboyAntiFacebook:[".util-bar-module-firefly-visible"],fanboyEnhancedTrackers:[".open.pushModal","#issuem-leaky-paywall-articles-zero-remaining-nag","#sovrn_container",'div[class$="-hide"][zoompage-fontsize][style="display: block;"]',".BlockNag__Card"],fanboySocial:["#FollowUs","#meteored_share","#social_follow",".article-sharer",".community__social-desc"],frellwitSwedish:[c("YVtocmVmKj0iY2FzaW5vcHJvLnNlIl1bdGFyZ2V0PSJfYmxhbmsiXQ=="),c("YVtocmVmKj0iZG9rdG9yLXNlLm9uZWxpbmsubWUiXQ=="),"article.category-samarbete",c("ZGl2LmhvbGlkQWRz"),"ul.adsmodern"],greekAdBlock:[c("QVtocmVmKj0iYWRtYW4ub3RlbmV0LmdyL2NsaWNrPyJd"),c("QVtocmVmKj0iaHR0cDovL2F4aWFiYW5uZXJzLmV4b2R1cy5nci8iXQ=="),c("QVtocmVmKj0iaHR0cDovL2ludGVyYWN0aXZlLmZvcnRobmV0LmdyL2NsaWNrPyJd"),"DIV.agores300","TABLE.advright"],hungarian:["#cemp_doboz",".optimonk-iframe-container",c("LmFkX19tYWlu"),c("W2NsYXNzKj0iR29vZ2xlQWRzIl0="),"#hirdetesek_box"],iDontCareAboutCookies:['.alert-info[data-block-track*="CookieNotice"]',".ModuleTemplateCookieIndicator",".o--cookies--container","#cookies-policy-sticky","#stickyCookieBar"],icelandicAbp:[c("QVtocmVmXj0iL2ZyYW1ld29yay9yZXNvdXJjZXMvZm9ybXMvYWRzLmFzcHgiXQ==")],latvian:[c("YVtocmVmPSJodHRwOi8vd3d3LnNhbGlkemluaS5sdi8iXVtzdHlsZT0iZGlzcGxheTogYmxvY2s7IHdpZHRoOiAxMjBweDsgaGVpZ2h0OiA0MHB4OyBvdmVyZmxvdzogaGlkZGVuOyBwb3NpdGlvbjogcmVsYXRpdmU7Il0="),c("YVtocmVmPSJodHRwOi8vd3d3LnNhbGlkemluaS5sdi8iXVtzdHlsZT0iZGlzcGxheTogYmxvY2s7IHdpZHRoOiA4OHB4OyBoZWlnaHQ6IDMxcHg7IG92ZXJmbG93OiBoaWRkZW47IHBvc2l0aW9uOiByZWxhdGl2ZTsiXQ==")],listKr:[c("YVtocmVmKj0iLy9hZC5wbGFuYnBsdXMuY28ua3IvIl0="),c("I2xpdmVyZUFkV3JhcHBlcg=="),c("YVtocmVmKj0iLy9hZHYuaW1hZHJlcC5jby5rci8iXQ=="),c("aW5zLmZhc3R2aWV3LWFk"),".revenue_unit_item.dable"],listeAr:[c("LmdlbWluaUxCMUFk"),".right-and-left-sponsers",c("YVtocmVmKj0iLmFmbGFtLmluZm8iXQ=="),c("YVtocmVmKj0iYm9vcmFxLm9yZyJd"),c("YVtocmVmKj0iZHViaXp6bGUuY29tL2FyLz91dG1fc291cmNlPSJd")],listeFr:[c("YVtocmVmXj0iaHR0cDovL3Byb21vLnZhZG9yLmNvbS8iXQ=="),c("I2FkY29udGFpbmVyX3JlY2hlcmNoZQ=="),c("YVtocmVmKj0id2Vib3JhbWEuZnIvZmNnaS1iaW4vIl0="),".site-pub-interstitiel",'div[id^="crt-"][data-criteo-id]'],officialPolish:["#ceneo-placeholder-ceneo-12",c("W2hyZWZePSJodHRwczovL2FmZi5zZW5kaHViLnBsLyJd"),c("YVtocmVmXj0iaHR0cDovL2Fkdm1hbmFnZXIudGVjaGZ1bi5wbC9yZWRpcmVjdC8iXQ=="),c("YVtocmVmXj0iaHR0cDovL3d3dy50cml6ZXIucGwvP3V0bV9zb3VyY2UiXQ=="),c("ZGl2I3NrYXBpZWNfYWQ=")],ro:[c("YVtocmVmXj0iLy9hZmZ0cmsuYWx0ZXgucm8vQ291bnRlci9DbGljayJd"),c("YVtocmVmXj0iaHR0cHM6Ly9ibGFja2ZyaWRheXNhbGVzLnJvL3Ryay9zaG9wLyJd"),c("YVtocmVmXj0iaHR0cHM6Ly9ldmVudC4ycGVyZm9ybWFudC5jb20vZXZlbnRzL2NsaWNrIl0="),c("YVtocmVmXj0iaHR0cHM6Ly9sLnByb2ZpdHNoYXJlLnJvLyJd"),'a[href^="/url/"]'],ruAd:[c("YVtocmVmKj0iLy9mZWJyYXJlLnJ1LyJd"),c("YVtocmVmKj0iLy91dGltZy5ydS8iXQ=="),c("YVtocmVmKj0iOi8vY2hpa2lkaWtpLnJ1Il0="),"#pgeldiz",".yandex-rtb-block"],thaiAds:["a[href*=macau-uta-popup]",c("I2Fkcy1nb29nbGUtbWlkZGxlX3JlY3RhbmdsZS1ncm91cA=="),c("LmFkczMwMHM="),".bumq",".img-kosana"],webAnnoyancesUltralist:["#mod-social-share-2","#social-tools",c("LmN0cGwtZnVsbGJhbm5lcg=="),".zergnet-recommend",".yt.btn-link.btn-md.btn"]},n=Object.keys(e),[4,T((i=[]).concat.apply(i,n.map((function(n){return e[n]}))))]):[2,void 0];case 1:return o=t.sent(),r&&function(e,n){for(var t="DOM blockers debug:\n```",r=0,o=Object.keys(e);r<o.length;r++){var a=o[r];t+="\n".concat(a,":");for(var i=0,c=e[a];i<c.length;i++){var u=c[i];t+="\n ".concat(n[u]?"🚫":"➡️"," ").concat(u)}}console.log("".concat(t,"\n```"))}(e,o),(a=n.filter((function(n){var t=e[n];return g(t.map((function(e){return o[e]})))>.6*t.length}))).sort(),[2,a]}var c}))}))},fontPreferences:function(){return function(e,n){void 0===n&&(n=4e3);return X((function(t,o){var a=o.document,i=a.body,c=i.style;c.width="".concat(n,"px"),c.webkitTextSizeAdjust=c.textSizeAdjust="none",S()?i.style.zoom="".concat(1/o.devicePixelRatio):x()&&(i.style.zoom="reset");var u=a.createElement("div");return u.textContent=r([],Array(n/20<<0),!0).map((function(){return"word"})).join(" "),i.appendChild(u),e(a,i)}),'<!doctype html><html><head><meta name="viewport" content="width=device-width, initial-scale=1">')}((function(e,n){for(var t={},r={},o=0,a=Object.keys(ee);o<a.length;o++){var i=a[o],c=ee[i],u=c[0],l=void 0===u?{}:u,s=c[1],d=void 0===s?"mmMwWLliI0fiflO&1":s,m=e.createElement("span");m.textContent=d,m.style.whiteSpace="nowrap";for(var f=0,v=Object.keys(l);f<v.length;f++){var h=v[f],p=l[h];void 0!==p&&(m.style[h]=p)}t[i]=m,n.appendChild(e.createElement("br")),n.appendChild(m)}for(var b=0,y=Object.keys(ee);b<y.length;b++){r[i=y[b]]=t[i].getBoundingClientRect().width}return r}))},audio:function(){var e=window,n=e.OfflineAudioContext||e.webkitOfflineAudioContext;if(!n)return-2;if(x()&&!F()&&!function(){var e=window;return g(["DOMRectList"in e,"RTCPeerConnectionIceEvent"in e,"SVGGeometryElement"in e,"ontransitioncancel"in e])>=3}())return-1;var t=new n(1,5e3,44100),r=t.createOscillator();r.type="triangle",r.frequency.value=1e4;var o=t.createDynamicsCompressor();o.threshold.value=-50,o.knee.value=40,o.ratio.value=12,o.attack.value=0,o.release.value=.25,r.connect(o),o.connect(t.destination),r.start(0);var i=function(e){var n=3,t=500,r=500,o=5e3,i=function(){};return[new Promise((function(c,l){var s=!1,d=0,m=0;e.oncomplete=function(e){return c(e.renderedBuffer)};var f=function(){setTimeout((function(){return l(R("timeout"))}),Math.min(r,m+o-Date.now()))},v=function(){try{var r=e.startRendering();switch(a(r)&&u(r),e.state){case"running":m=Date.now(),s&&f();break;case"suspended":document.hidden||d++,s&&d>=n?l(R("suspended")):setTimeout(v,t)}}catch(o){l(o)}};v(),i=function(){s||(s=!0,m>0&&f())}})),i]}(t),c=i[0],l=i[1],s=c.then((function(e){return function(e){for(var n=0,t=0;t<e.length;++t)n+=Math.abs(e[t]);return n}(e.getChannelData(0).subarray(4500))}),(function(e){if("timeout"===e.name||"suspended"===e.name)return-3;throw e}));return u(s),function(){return l(),s}},screenFrame:function(){var e=this,r=z();return function(){return n(e,void 0,void 0,(function(){var e,n;return t(this,(function(t){switch(t.label){case 0:return[4,r()];case 1:return e=t.sent(),[2,[(n=function(e){return null===e?null:w(e,10)})(e[0]),n(e[1]),n(e[2]),n(e[3])]]}}))}))}},osCpu:function(){return navigator.oscpu},languages:function(){var e,n=navigator,t=[],r=n.language||n.userLanguage||n.browserLanguage||n.systemLanguage;if(void 0!==r&&t.push([r]),Array.isArray(n.languages))S()&&g([!("MediaSettingsRange"in(e=window)),"RTCEncodedAudioFrame"in e,""+e.Intl=="[object Intl]",""+e.Reflect=="[object Reflect]"])>=3||t.push(n.languages);else if("string"==typeof n.languages){var o=n.languages;o&&t.push(o.split(","))}return t},colorDepth:function(){return window.screen.colorDepth},deviceMemory:function(){return y(b(navigator.deviceMemory),void 0)},screenResolution:function(){var e=screen,n=function(e){return y(p(e),null)},t=[n(e.width),n(e.height)];return t.sort().reverse(),t},hardwareConcurrency:function(){return y(p(navigator.hardwareConcurrency),void 0)},timezone:function(){var e,n=null===(e=window.Intl)||void 0===e?void 0:e.DateTimeFormat;if(n){var t=(new n).resolvedOptions().timeZone;if(t)return t}var r,o=(r=(new Date).getFullYear(),-Math.max(b(new Date(r,0,1).getTimezoneOffset()),b(new Date(r,6,1).getTimezoneOffset())));return"UTC".concat(o>=0?"+":"").concat(Math.abs(o))},sessionStorage:function(){try{return!!window.sessionStorage}catch(e){return!0}},localStorage:function(){try{return!!window.localStorage}catch(e){return!0}},indexedDB:function(){if(!W()&&!C())try{return!!window.indexedDB}catch(e){return!0}},openDatabase:function(){return!!window.openDatabase},cpuClass:function(){return navigator.cpuClass},platform:function(){var e=navigator.platform;return"MacIntel"===e&&x()&&!F()?function(){if("iPad"===navigator.platform)return!0;var e=screen,n=e.width/e.height;return g(["MediaSource"in window,!!Element.prototype.webkitRequestFullscreen,n>.65&&n<1.53])>=2}()?"iPad":"iPhone":e},plugins:function(){var e=navigator.plugins;if(e){for(var n=[],t=0;t<e.length;++t){var r=e[t];if(r){for(var o=[],a=0;a<r.length;++a){var i=r[a];o.push({type:i.type,suffixes:i.suffixes})}n.push({name:r.name,description:r.description,mimeTypes:o})}}return n}},canvas:function(){var e,n,t=!1,r=function(){var e=document.createElement("canvas");return e.width=1,e.height=1,[e,e.getContext("2d")]}(),o=r[0],a=r[1];if(function(e,n){return!(!n||!e.toDataURL)}(o,a)){t=function(e){return e.rect(0,0,10,10),e.rect(2,2,6,6),!e.isPointInPath(5,5,"evenodd")}(a),function(e,n){e.width=240,e.height=60,n.textBaseline="alphabetic",n.fillStyle="#f60",n.fillRect(100,1,62,20),n.fillStyle="#069",n.font='11pt "Times New Roman"';var t="Cwm fjordbank gly ".concat(String.fromCharCode(55357,56835));n.fillText(t,2,15),n.fillStyle="rgba(102, 204, 0, 0.2)",n.font="18pt Arial",n.fillText(t,4,45)}(o,a);var i=H(o);i!==H(o)?e=n="unstable":(n=i,function(e,n){e.width=122,e.height=110,n.globalCompositeOperation="multiply";for(var t=0,r=[["#f2f",40,40],["#2ff",80,40],["#ff2",60,80]];t<r.length;t++){var o=r[t],a=o[0],i=o[1],c=o[2];n.fillStyle=a,n.beginPath(),n.arc(i,c,40,0,2*Math.PI,!0),n.closePath(),n.fill()}n.fillStyle="#f9c",n.arc(60,60,60,0,2*Math.PI,!0),n.arc(60,60,20,0,2*Math.PI,!0),n.fill("evenodd")}(o,a),e=H(o))}else e=n="";return{winding:t,geometry:e,text:n}},touchSupport:function(){var e,n=navigator,t=0;void 0!==n.maxTouchPoints?t=p(n.maxTouchPoints):void 0!==n.msMaxTouchPoints&&(t=n.msMaxTouchPoints);try{document.createEvent("TouchEvent"),e=!0}catch(r){e=!1}return{maxTouchPoints:t,touchEvent:e,touchStart:"ontouchstart"in window}},vendor:function(){return navigator.vendor||""},vendorFlavors:function(){for(var e=[],n=0,t=["chrome","safari","__crWeb","__gCrWeb","yandex","__yb","__ybro","__firefox__","__edgeTrackingPreventionStatistics","webkit","oprt","samsungAr","ucweb","UCShellJava","puffinDevice"];n<t.length;n++){var r=t[n],o=window[r];o&&"object"==typeof o&&e.push(r)}return e.sort()},cookiesEnabled:function(){var e=document;try{e.cookie="cookietest=1; SameSite=Strict;";var n=-1!==e.cookie.indexOf("cookietest=");return e.cookie="cookietest=1; SameSite=Strict; expires=Thu, 01-Jan-1970 00:00:01 GMT",n}catch(t){return!1}},colorGamut:function(){for(var e=0,n=["rec2020","p3","srgb"];e<n.length;e++){var t=n[e];if(matchMedia("(color-gamut: ".concat(t,")")).matches)return t}},invertedColors:function(){return!!_("inverted")||!_("none")&&void 0},forcedColors:function(){return!!O("active")||!O("none")&&void 0},monochrome:function(){if(matchMedia("(min-monochrome: 0)").matches){for(var e=0;e<=100;++e)if(matchMedia("(max-monochrome: ".concat(e,")")).matches)return e;throw new Error("Too high value")}},contrast:function(){return U("no-preference")?0:U("high")||U("more")?1:U("low")||U("less")?-1:U("forced")?10:void 0},reducedMotion:function(){return!!Q("reduce")||!Q("no-preference")&&void 0},hdr:function(){return!!K("high")||!K("standard")&&void 0},math:function(){var e,n=q.acos||$,t=q.acosh||$,r=q.asin||$,o=q.asinh||$,a=q.atanh||$,i=q.atan||$,c=q.sin||$,u=q.sinh||$,l=q.cos||$,s=q.cosh||$,d=q.tan||$,m=q.tanh||$,f=q.exp||$,v=q.expm1||$,h=q.log1p||$;return{acos:n(.12312423423423424),acosh:t(1e308),acoshPf:(e=1e154,q.log(e+q.sqrt(e*e-1))),asin:r(.12312423423423424),asinh:o(1),asinhPf:function(e){return q.log(e+q.sqrt(e*e+1))}(1),atanh:a(.5),atanhPf:function(e){return q.log((1+e)/(1-e))/2}(.5),atan:i(.5),sin:c(-1e300),sinh:u(1),sinhPf:function(e){return q.exp(e)-1/q.exp(e)/2}(1),cos:l(10.000000000123),cosh:s(1),coshPf:function(e){return(q.exp(e)+1/q.exp(e))/2}(1),tan:d(-1e300),tanh:m(1),tanhPf:function(e){return(q.exp(2*e)-1)/(q.exp(2*e)+1)}(1),exp:f(1),expm1:v(1),expm1Pf:function(e){return q.exp(e)-1}(1),log1p:h(10),log1pPf:function(e){return q.log(1+e)}(10),powPI:function(e){return q.pow(q.PI,e)}(-100)}},videoCard:function(){var e,n=document.createElement("canvas"),t=null!==(e=n.getContext("webgl"))&&void 0!==e?e:n.getContext("experimental-webgl");if(t&&"getExtension"in t){var r=t.getExtension("WEBGL_debug_renderer_info");if(r)return{vendor:(t.getParameter(r.UNMASKED_VENDOR_WEBGL)||"").toString(),renderer:(t.getParameter(r.UNMASKED_RENDERER_WEBGL)||"").toString()}}},pdfViewerEnabled:function(){return navigator.pdfViewerEnabled},architecture:function(){var e=new Float32Array(1),n=new Uint8Array(e.buffer);return e[0]=1/0,e[0]=e[0]-e[0],n[3]}};function te(e){var n=function(e){if(G())return.4;if(x())return F()?.5:.3;var n=e.platform.value||"";if(/^Win/.test(n))return.6;if(/^Mac/.test(n))return.5;return.7}(e),t=function(e){return w(.99+.01*e,1e-4)}(n);return{score:n,comment:"$ if upgrade to Pro: https://fpjs.dev/pro".replace(/\$/g,"".concat(t))}}function re(n){return JSON.stringify(n,(function(n,t){return t instanceof Error?e({name:(r=t).name,message:r.message,stack:null===(o=r.stack)||void 0===o?void 0:o.split("\n")},r):t;var r,o}),2)}function oe(e){return h(function(e){for(var n="",t=0,r=Object.keys(e).sort();t<r.length;t++){var o=r[t],a=e[o],i=a.error?"error":JSON.stringify(a.value);n+="".concat(n?"|":"").concat(o.replace(/([:|\\])/g,"\\$1"),":").concat(i)}return n}(e))}function ae(e){return void 0===e&&(e=50),function(e,n){void 0===n&&(n=1/0);var t=window.requestIdleCallback;return t?new Promise((function(e){return t.call(window,(function(){return e()}),{timeout:n})})):o(Math.min(e,n))}(e,2*e)}function ie(e,r){var o=Date.now();return{get:function(a){return n(this,void 0,void 0,(function(){var n,i,c;return t(this,(function(t){switch(t.label){case 0:return n=Date.now(),[4,e()];case 1:return i=t.sent(),c=function(e){var n;return{get visitorId(){return void 0===n&&(n=oe(this.components)),n},set visitorId(e){n=e},confidence:te(e),components:e,version:"3.4.2"}}(i),(r||(null==a?void 0:a.debug))&&console.log("Copy the text below to get the debug data:\n\n```\nversion: ".concat(c.version,"\nuserAgent: ").concat(navigator.userAgent,"\ntimeBetweenLoadAndGet: ").concat(n-o,"\nvisitorId: ").concat(c.visitorId,"\ncomponents: ").concat(re(i),"\n```")),[2,c]}}))}))}}}function ce(e){var r=void 0===e?{}:e,o=r.delayFallback,a=r.debug;return r.monitoring,n(this,void 0,void 0,(function(){return t(this,(function(e){switch(e.label){case 0:return[4,ae(o)];case 1:return e.sent(),[2,ie(V(ne,{debug:a},[]),a)]}}))}))}var ue={load:ce,hashComponents:oe,componentsToDebugString:re},le=h;export{re as componentsToDebugString,ue as default,M as getFullscreenElement,z as getScreenFrame,oe as hashComponents,G as isAndroid,S as isChromium,F as isDesktopSafari,C as isEdgeHTML,Y as isGecko,W as isTrident,x as isWebKit,ce as load,V as loadSources,le as murmurX64Hash128,ae as prepareForSources,ne as sources,Z as transformSource,X as withIframe};