outhad-integrations 0.32.0

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.
Files changed (275) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +43 -0
  4. data/.ruby-version +1 -0
  5. data/.vscode/settings.json +5 -0
  6. data/README.md +76 -0
  7. data/Rakefile +12 -0
  8. data/lib/outhad/integrations/config.rb +14 -0
  9. data/lib/outhad/integrations/core/base_connector.rb +79 -0
  10. data/lib/outhad/integrations/core/constants.rb +103 -0
  11. data/lib/outhad/integrations/core/destination_connector.rb +20 -0
  12. data/lib/outhad/integrations/core/fullrefresher.rb +19 -0
  13. data/lib/outhad/integrations/core/http_client.rb +17 -0
  14. data/lib/outhad/integrations/core/http_helper.rb +36 -0
  15. data/lib/outhad/integrations/core/query_builder.rb +33 -0
  16. data/lib/outhad/integrations/core/rate_limiter.rb +19 -0
  17. data/lib/outhad/integrations/core/source_connector.rb +66 -0
  18. data/lib/outhad/integrations/core/streaming_http_client.rb +21 -0
  19. data/lib/outhad/integrations/core/unstructured_source_connector.rb +52 -0
  20. data/lib/outhad/integrations/core/utils.rb +123 -0
  21. data/lib/outhad/integrations/core/vector_source_connector.rb +14 -0
  22. data/lib/outhad/integrations/destination/airtable/client.rb +157 -0
  23. data/lib/outhad/integrations/destination/airtable/config/catalog.json +6 -0
  24. data/lib/outhad/integrations/destination/airtable/config/meta.json +15 -0
  25. data/lib/outhad/integrations/destination/airtable/config/spec.json +23 -0
  26. data/lib/outhad/integrations/destination/airtable/icon.svg +6 -0
  27. data/lib/outhad/integrations/destination/airtable/schema_helper.rb +141 -0
  28. data/lib/outhad/integrations/destination/ais_data_store/client.rb +130 -0
  29. data/lib/outhad/integrations/destination/ais_data_store/config/meta.json +15 -0
  30. data/lib/outhad/integrations/destination/ais_data_store/config/spec.json +68 -0
  31. data/lib/outhad/integrations/destination/ais_data_store/icon.svg +4 -0
  32. data/lib/outhad/integrations/destination/amazon_s3/client.rb +92 -0
  33. data/lib/outhad/integrations/destination/amazon_s3/config/catalog.json +16 -0
  34. data/lib/outhad/integrations/destination/amazon_s3/config/meta.json +15 -0
  35. data/lib/outhad/integrations/destination/amazon_s3/config/spec.json +56 -0
  36. data/lib/outhad/integrations/destination/amazon_s3/icon.svg +34 -0
  37. data/lib/outhad/integrations/destination/databricks_lakehouse/client.rb +147 -0
  38. data/lib/outhad/integrations/destination/databricks_lakehouse/config/meta.json +15 -0
  39. data/lib/outhad/integrations/destination/databricks_lakehouse/config/spec.json +44 -0
  40. data/lib/outhad/integrations/destination/databricks_lakehouse/icon.svg +65 -0
  41. data/lib/outhad/integrations/destination/facebook_custom_audience/client.rb +125 -0
  42. data/lib/outhad/integrations/destination/facebook_custom_audience/config/catalog.json +42 -0
  43. data/lib/outhad/integrations/destination/facebook_custom_audience/config/meta.json +15 -0
  44. data/lib/outhad/integrations/destination/facebook_custom_audience/config/spec.json +28 -0
  45. data/lib/outhad/integrations/destination/facebook_custom_audience/icon.svg +23 -0
  46. data/lib/outhad/integrations/destination/google_sheets/client.rb +240 -0
  47. data/lib/outhad/integrations/destination/google_sheets/config/catalog.json +6 -0
  48. data/lib/outhad/integrations/destination/google_sheets/config/meta.json +15 -0
  49. data/lib/outhad/integrations/destination/google_sheets/config/spec.json +75 -0
  50. data/lib/outhad/integrations/destination/google_sheets/icon.svg +1 -0
  51. data/lib/outhad/integrations/destination/http/client.rb +106 -0
  52. data/lib/outhad/integrations/destination/http/config/catalog.json +16 -0
  53. data/lib/outhad/integrations/destination/http/config/meta.json +15 -0
  54. data/lib/outhad/integrations/destination/http/config/spec.json +24 -0
  55. data/lib/outhad/integrations/destination/http/icon.svg +9 -0
  56. data/lib/outhad/integrations/destination/hubspot/client.rb +122 -0
  57. data/lib/outhad/integrations/destination/hubspot/config/catalog.json +351 -0
  58. data/lib/outhad/integrations/destination/hubspot/config/meta.json +15 -0
  59. data/lib/outhad/integrations/destination/hubspot/config/spec.json +18 -0
  60. data/lib/outhad/integrations/destination/hubspot/icon.svg +5 -0
  61. data/lib/outhad/integrations/destination/iterable/client.rb +111 -0
  62. data/lib/outhad/integrations/destination/iterable/config/catalog.json +47 -0
  63. data/lib/outhad/integrations/destination/iterable/config/meta.json +15 -0
  64. data/lib/outhad/integrations/destination/iterable/config/spec.json +19 -0
  65. data/lib/outhad/integrations/destination/iterable/icon.svg +71 -0
  66. data/lib/outhad/integrations/destination/klaviyo/client.rb +119 -0
  67. data/lib/outhad/integrations/destination/klaviyo/config/catalog.json +103 -0
  68. data/lib/outhad/integrations/destination/klaviyo/config/meta.json +15 -0
  69. data/lib/outhad/integrations/destination/klaviyo/config/spec.json +24 -0
  70. data/lib/outhad/integrations/destination/klaviyo/icon.svg +6 -0
  71. data/lib/outhad/integrations/destination/mailchimp/client.rb +141 -0
  72. data/lib/outhad/integrations/destination/mailchimp/config/catalog.json +142 -0
  73. data/lib/outhad/integrations/destination/mailchimp/config/meta.json +15 -0
  74. data/lib/outhad/integrations/destination/mailchimp/config/spec.json +28 -0
  75. data/lib/outhad/integrations/destination/mailchimp/icon.svg +4 -0
  76. data/lib/outhad/integrations/destination/maria_db/client.rb +114 -0
  77. data/lib/outhad/integrations/destination/maria_db/config/meta.json +15 -0
  78. data/lib/outhad/integrations/destination/maria_db/config/spec.json +48 -0
  79. data/lib/outhad/integrations/destination/maria_db/icon.svg +15 -0
  80. data/lib/outhad/integrations/destination/microsoft_dynamics/client.rb +150 -0
  81. data/lib/outhad/integrations/destination/microsoft_dynamics/config/catalog.json +161 -0
  82. data/lib/outhad/integrations/destination/microsoft_dynamics/config/meta.json +15 -0
  83. data/lib/outhad/integrations/destination/microsoft_dynamics/config/spec.json +35 -0
  84. data/lib/outhad/integrations/destination/microsoft_dynamics/icon.svg +2 -0
  85. data/lib/outhad/integrations/destination/microsoft_excel/client.rb +198 -0
  86. data/lib/outhad/integrations/destination/microsoft_excel/config/catalog.json +7 -0
  87. data/lib/outhad/integrations/destination/microsoft_excel/config/meta.json +15 -0
  88. data/lib/outhad/integrations/destination/microsoft_excel/config/spec.json +19 -0
  89. data/lib/outhad/integrations/destination/microsoft_excel/icon.svg +18 -0
  90. data/lib/outhad/integrations/destination/microsoft_sql/client.rb +137 -0
  91. data/lib/outhad/integrations/destination/microsoft_sql/config/meta.json +15 -0
  92. data/lib/outhad/integrations/destination/microsoft_sql/config/spec.json +68 -0
  93. data/lib/outhad/integrations/destination/microsoft_sql/icon.svg +22 -0
  94. data/lib/outhad/integrations/destination/odoo/client.rb +109 -0
  95. data/lib/outhad/integrations/destination/odoo/config/meta.json +15 -0
  96. data/lib/outhad/integrations/destination/odoo/config/spec.json +39 -0
  97. data/lib/outhad/integrations/destination/odoo/icon.svg +21 -0
  98. data/lib/outhad/integrations/destination/oracle_db/client.rb +112 -0
  99. data/lib/outhad/integrations/destination/oracle_db/config/meta.json +15 -0
  100. data/lib/outhad/integrations/destination/oracle_db/config/spec.json +47 -0
  101. data/lib/outhad/integrations/destination/oracle_db/icon.svg +4 -0
  102. data/lib/outhad/integrations/destination/pinecone_db/client.rb +154 -0
  103. data/lib/outhad/integrations/destination/pinecone_db/config/meta.json +15 -0
  104. data/lib/outhad/integrations/destination/pinecone_db/config/spec.json +32 -0
  105. data/lib/outhad/integrations/destination/pinecone_db/icon.svg +1 -0
  106. data/lib/outhad/integrations/destination/postgresql/client.rb +130 -0
  107. data/lib/outhad/integrations/destination/postgresql/config/meta.json +15 -0
  108. data/lib/outhad/integrations/destination/postgresql/config/spec.json +68 -0
  109. data/lib/outhad/integrations/destination/postgresql/icon.svg +20 -0
  110. data/lib/outhad/integrations/destination/qdrant/client.rb +184 -0
  111. data/lib/outhad/integrations/destination/qdrant/config/meta.json +15 -0
  112. data/lib/outhad/integrations/destination/qdrant/config/spec.json +23 -0
  113. data/lib/outhad/integrations/destination/qdrant/icon.svg +1 -0
  114. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/client.rb +136 -0
  115. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/catalog.json +6 -0
  116. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/meta.json +16 -0
  117. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/spec.json +52 -0
  118. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/icon.svg +16 -0
  119. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/schema_helper.rb +132 -0
  120. data/lib/outhad/integrations/destination/salesforce_crm/client.rb +114 -0
  121. data/lib/outhad/integrations/destination/salesforce_crm/config/catalog.json +320 -0
  122. data/lib/outhad/integrations/destination/salesforce_crm/config/meta.json +15 -0
  123. data/lib/outhad/integrations/destination/salesforce_crm/config/spec.json +46 -0
  124. data/lib/outhad/integrations/destination/salesforce_crm/icon.svg +16 -0
  125. data/lib/outhad/integrations/destination/sftp/client.rb +186 -0
  126. data/lib/outhad/integrations/destination/sftp/config/catalog.json +16 -0
  127. data/lib/outhad/integrations/destination/sftp/config/meta.json +16 -0
  128. data/lib/outhad/integrations/destination/sftp/config/spec.json +73 -0
  129. data/lib/outhad/integrations/destination/sftp/icon.svg +1 -0
  130. data/lib/outhad/integrations/destination/slack/client.rb +125 -0
  131. data/lib/outhad/integrations/destination/slack/config/catalog.json +22 -0
  132. data/lib/outhad/integrations/destination/slack/config/meta.json +15 -0
  133. data/lib/outhad/integrations/destination/slack/config/spec.json +23 -0
  134. data/lib/outhad/integrations/destination/slack/icon.svg +26 -0
  135. data/lib/outhad/integrations/destination/stripe/client.rb +94 -0
  136. data/lib/outhad/integrations/destination/stripe/config/catalog.json +128 -0
  137. data/lib/outhad/integrations/destination/stripe/config/meta.json +15 -0
  138. data/lib/outhad/integrations/destination/stripe/config/spec.json +18 -0
  139. data/lib/outhad/integrations/destination/stripe/icon.svg +10 -0
  140. data/lib/outhad/integrations/destination/zendesk/client.rb +132 -0
  141. data/lib/outhad/integrations/destination/zendesk/config/catalog.json +110 -0
  142. data/lib/outhad/integrations/destination/zendesk/config/meta.json +18 -0
  143. data/lib/outhad/integrations/destination/zendesk/config/spec.json +32 -0
  144. data/lib/outhad/integrations/destination/zendesk/icon.svg +63 -0
  145. data/lib/outhad/integrations/protocol/protocol.json +189 -0
  146. data/lib/outhad/integrations/protocol/protocol.rb +228 -0
  147. data/lib/outhad/integrations/rollout.rb +66 -0
  148. data/lib/outhad/integrations/service.rb +55 -0
  149. data/lib/outhad/integrations/source/amazon_s3/client.rb +235 -0
  150. data/lib/outhad/integrations/source/amazon_s3/config/meta.json +16 -0
  151. data/lib/outhad/integrations/source/amazon_s3/config/spec.json +119 -0
  152. data/lib/outhad/integrations/source/amazon_s3/icon.svg +34 -0
  153. data/lib/outhad/integrations/source/anthropic/client.rb +135 -0
  154. data/lib/outhad/integrations/source/anthropic/config/catalog.json +6 -0
  155. data/lib/outhad/integrations/source/anthropic/config/meta.json +16 -0
  156. data/lib/outhad/integrations/source/anthropic/config/spec.json +56 -0
  157. data/lib/outhad/integrations/source/anthropic/icon.svg +1 -0
  158. data/lib/outhad/integrations/source/aws_athena/client.rb +109 -0
  159. data/lib/outhad/integrations/source/aws_athena/config/meta.json +16 -0
  160. data/lib/outhad/integrations/source/aws_athena/config/spec.json +63 -0
  161. data/lib/outhad/integrations/source/aws_athena/icon.svg +22 -0
  162. data/lib/outhad/integrations/source/aws_bedrock_model/client.rb +91 -0
  163. data/lib/outhad/integrations/source/aws_bedrock_model/config/catalog.json +6 -0
  164. data/lib/outhad/integrations/source/aws_bedrock_model/config/meta.json +16 -0
  165. data/lib/outhad/integrations/source/aws_bedrock_model/config/spec.json +58 -0
  166. data/lib/outhad/integrations/source/aws_bedrock_model/icon.svg +1 -0
  167. data/lib/outhad/integrations/source/aws_sagemaker_model/client.rb +79 -0
  168. data/lib/outhad/integrations/source/aws_sagemaker_model/config/catalog.json +6 -0
  169. data/lib/outhad/integrations/source/aws_sagemaker_model/config/meta.json +16 -0
  170. data/lib/outhad/integrations/source/aws_sagemaker_model/config/spec.json +52 -0
  171. data/lib/outhad/integrations/source/aws_sagemaker_model/icon.svg +7 -0
  172. data/lib/outhad/integrations/source/bigquery/client.rb +98 -0
  173. data/lib/outhad/integrations/source/bigquery/config/meta.json +16 -0
  174. data/lib/outhad/integrations/source/bigquery/config/spec.json +83 -0
  175. data/lib/outhad/integrations/source/bigquery/icon.svg +1 -0
  176. data/lib/outhad/integrations/source/clickhouse/client.rb +102 -0
  177. data/lib/outhad/integrations/source/clickhouse/config/meta.json +16 -0
  178. data/lib/outhad/integrations/source/clickhouse/config/spec.json +42 -0
  179. data/lib/outhad/integrations/source/clickhouse/icon.svg +25 -0
  180. data/lib/outhad/integrations/source/databricks/client.rb +98 -0
  181. data/lib/outhad/integrations/source/databricks/config/meta.json +17 -0
  182. data/lib/outhad/integrations/source/databricks/config/spec.json +56 -0
  183. data/lib/outhad/integrations/source/databricks/icon.svg +19 -0
  184. data/lib/outhad/integrations/source/databrics_model/client.rb +89 -0
  185. data/lib/outhad/integrations/source/databrics_model/config/catalog.json +6 -0
  186. data/lib/outhad/integrations/source/databrics_model/config/meta.json +17 -0
  187. data/lib/outhad/integrations/source/databrics_model/config/spec.json +63 -0
  188. data/lib/outhad/integrations/source/databrics_model/icon.svg +19 -0
  189. data/lib/outhad/integrations/source/firecrawl/client.rb +151 -0
  190. data/lib/outhad/integrations/source/firecrawl/config/catalog.json +29 -0
  191. data/lib/outhad/integrations/source/firecrawl/config/meta.json +17 -0
  192. data/lib/outhad/integrations/source/firecrawl/config/spec.json +31 -0
  193. data/lib/outhad/integrations/source/firecrawl/icon.svg +4 -0
  194. data/lib/outhad/integrations/source/generic_open_ai/client.rb +118 -0
  195. data/lib/outhad/integrations/source/generic_open_ai/config/catalog.json +6 -0
  196. data/lib/outhad/integrations/source/generic_open_ai/config/meta.json +16 -0
  197. data/lib/outhad/integrations/source/generic_open_ai/config/spec.json +63 -0
  198. data/lib/outhad/integrations/source/generic_open_ai/icon.svg +6 -0
  199. data/lib/outhad/integrations/source/google_vertex_model/client.rb +83 -0
  200. data/lib/outhad/integrations/source/google_vertex_model/config/catalog.json +6 -0
  201. data/lib/outhad/integrations/source/google_vertex_model/config/meta.json +17 -0
  202. data/lib/outhad/integrations/source/google_vertex_model/config/spec.json +105 -0
  203. data/lib/outhad/integrations/source/google_vertex_model/icon.svg +2 -0
  204. data/lib/outhad/integrations/source/http_model/client.rb +108 -0
  205. data/lib/outhad/integrations/source/http_model/config/catalog.json +6 -0
  206. data/lib/outhad/integrations/source/http_model/config/meta.json +16 -0
  207. data/lib/outhad/integrations/source/http_model/config/spec.json +70 -0
  208. data/lib/outhad/integrations/source/http_model/icon.svg +9 -0
  209. data/lib/outhad/integrations/source/intuit_quick_books/client.rb +213 -0
  210. data/lib/outhad/integrations/source/intuit_quick_books/config/catalog.json +6 -0
  211. data/lib/outhad/integrations/source/intuit_quick_books/config/meta.json +17 -0
  212. data/lib/outhad/integrations/source/intuit_quick_books/config/spec.json +44 -0
  213. data/lib/outhad/integrations/source/intuit_quick_books/icon.svg +1 -0
  214. data/lib/outhad/integrations/source/maria_db/client.rb +92 -0
  215. data/lib/outhad/integrations/source/maria_db/config/meta.json +16 -0
  216. data/lib/outhad/integrations/source/maria_db/config/spec.json +48 -0
  217. data/lib/outhad/integrations/source/maria_db/icon.svg +15 -0
  218. data/lib/outhad/integrations/source/odoo/client.rb +106 -0
  219. data/lib/outhad/integrations/source/odoo/config/meta.json +15 -0
  220. data/lib/outhad/integrations/source/odoo/config/spec.json +39 -0
  221. data/lib/outhad/integrations/source/odoo/icon.svg +21 -0
  222. data/lib/outhad/integrations/source/open_ai/client.rb +118 -0
  223. data/lib/outhad/integrations/source/open_ai/config/catalog.json +6 -0
  224. data/lib/outhad/integrations/source/open_ai/config/meta.json +16 -0
  225. data/lib/outhad/integrations/source/open_ai/config/spec.json +56 -0
  226. data/lib/outhad/integrations/source/open_ai/icon.svg +1 -0
  227. data/lib/outhad/integrations/source/oracle_db/client.rb +127 -0
  228. data/lib/outhad/integrations/source/oracle_db/config/meta.json +16 -0
  229. data/lib/outhad/integrations/source/oracle_db/config/spec.json +47 -0
  230. data/lib/outhad/integrations/source/oracle_db/icon.svg +4 -0
  231. data/lib/outhad/integrations/source/pinecone_db/client.rb +73 -0
  232. data/lib/outhad/integrations/source/pinecone_db/config/catalog.json +6 -0
  233. data/lib/outhad/integrations/source/pinecone_db/config/meta.json +16 -0
  234. data/lib/outhad/integrations/source/pinecone_db/config/spec.json +34 -0
  235. data/lib/outhad/integrations/source/pinecone_db/icon.svg +2 -0
  236. data/lib/outhad/integrations/source/postgresql/client.rb +112 -0
  237. data/lib/outhad/integrations/source/postgresql/config/meta.json +16 -0
  238. data/lib/outhad/integrations/source/postgresql/config/spec.json +86 -0
  239. data/lib/outhad/integrations/source/postgresql/icon.svg +20 -0
  240. data/lib/outhad/integrations/source/qdrant/client.rb +86 -0
  241. data/lib/outhad/integrations/source/qdrant/config/catalog.json +6 -0
  242. data/lib/outhad/integrations/source/qdrant/config/meta.json +16 -0
  243. data/lib/outhad/integrations/source/qdrant/config/spec.json +29 -0
  244. data/lib/outhad/integrations/source/qdrant/icon.svg +1 -0
  245. data/lib/outhad/integrations/source/redshift/client.rb +109 -0
  246. data/lib/outhad/integrations/source/redshift/config/meta.json +16 -0
  247. data/lib/outhad/integrations/source/redshift/config/spec.json +71 -0
  248. data/lib/outhad/integrations/source/redshift/icon.svg +15 -0
  249. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/client.rb +133 -0
  250. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/catalog.json +6 -0
  251. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/meta.json +18 -0
  252. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/spec.json +53 -0
  253. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/icon.svg +16 -0
  254. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/schema_helper.rb +130 -0
  255. data/lib/outhad/integrations/source/sftp/client.rb +133 -0
  256. data/lib/outhad/integrations/source/sftp/config/meta.json +16 -0
  257. data/lib/outhad/integrations/source/sftp/config/spec.json +59 -0
  258. data/lib/outhad/integrations/source/sftp/icon.svg +1 -0
  259. data/lib/outhad/integrations/source/snowflake/client.rb +92 -0
  260. data/lib/outhad/integrations/source/snowflake/config/meta.json +16 -0
  261. data/lib/outhad/integrations/source/snowflake/config/spec.json +82 -0
  262. data/lib/outhad/integrations/source/snowflake/icon.svg +10 -0
  263. data/lib/outhad/integrations/source/watsonx_ai/client.rb +194 -0
  264. data/lib/outhad/integrations/source/watsonx_ai/config/catalog.json +6 -0
  265. data/lib/outhad/integrations/source/watsonx_ai/config/meta.json +16 -0
  266. data/lib/outhad/integrations/source/watsonx_ai/config/spec.json +74 -0
  267. data/lib/outhad/integrations/source/watsonx_ai/icon.svg +1 -0
  268. data/lib/outhad/integrations/source/watsonx_data/client.rb +146 -0
  269. data/lib/outhad/integrations/source/watsonx_data/config/meta.json +17 -0
  270. data/lib/outhad/integrations/source/watsonx_data/config/spec.json +72 -0
  271. data/lib/outhad/integrations/source/watsonx_data/icon.svg +1 -0
  272. data/lib/outhad/integrations.rb +129 -0
  273. data/outhad-integrations.gemspec +79 -0
  274. data/sig/outhad/integrations.rbs +6 -0
  275. metadata +866 -0
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad::Integrations::Destination
4
+ module FacebookCustomAudience
5
+ include Outhad::Integrations::Core
6
+ class Client < DestinationConnector
7
+ prepend Outhad::Integrations::Core::RateLimiter
8
+ MAX_CHUNK_SIZE = 10_000
9
+ def check_connection(connection_config)
10
+ connection_config = connection_config.with_indifferent_access
11
+ access_token = connection_config[:access_token]
12
+ response = Outhad::Integrations::Core::HttpClient.request(
13
+ FACEBOOK_AUDIENCE_GET_ALL_ACCOUNTS,
14
+ HTTP_GET,
15
+ headers: auth_headers(access_token)
16
+ )
17
+ if success?(response)
18
+ ad_account_exists?(response, connection_config[:ad_account_id])
19
+ ConnectionStatus.new(status: ConnectionStatusType["succeeded"]).to_outhad_message
20
+ else
21
+ ConnectionStatus.new(status: ConnectionStatusType["failed"]).to_outhad_message
22
+ end
23
+ rescue StandardError => e
24
+ ConnectionStatus.new(status: ConnectionStatusType["failed"], message: e.message).to_outhad_message
25
+ end
26
+
27
+ def discover(_connection_config = nil)
28
+ catalog_json = read_json(CATALOG_SPEC_PATH)
29
+ catalog = build_catalog(catalog_json)
30
+ catalog.to_outhad_message
31
+ rescue StandardError => e
32
+ handle_exception(e, {
33
+ context: "FACEBOOK AUDIENCE:DISCOVER:EXCEPTION",
34
+ type: "error"
35
+ })
36
+ end
37
+
38
+ def write(sync_config, records, _action = "destination_insert")
39
+ connection_config = sync_config.destination.connection_specification.with_indifferent_access
40
+ access_token = connection_config[:access_token]
41
+ url = generate_url(sync_config, connection_config)
42
+ write_success = 0
43
+ write_failure = 0
44
+ records.each_slice(MAX_CHUNK_SIZE) do |chunk|
45
+ payload = create_payload(chunk, sync_config.stream.json_schema.with_indifferent_access)
46
+ response = Outhad::Integrations::Core::HttpClient.request(
47
+ url,
48
+ sync_config.stream.request_method,
49
+ payload: payload,
50
+ headers: auth_headers(access_token)
51
+ )
52
+ if success?(response)
53
+ write_success += chunk.size
54
+ else
55
+ write_failure += chunk.size
56
+ end
57
+ rescue StandardError => e
58
+ handle_exception(e, {
59
+ context: "FACEBOOK:RECORD:WRITE:EXCEPTION",
60
+ type: "error",
61
+ sync_id: sync_config.sync_id,
62
+ sync_run_id: sync_config.sync_run_id
63
+ })
64
+ write_failure += chunk.size
65
+ end
66
+
67
+ tracker = Outhad::Integrations::Protocol::TrackingMessage.new(
68
+ success: write_success,
69
+ failed: write_failure
70
+ )
71
+ tracker.to_outhad_message
72
+ rescue StandardError => e
73
+ handle_exception(e, {
74
+ context: "FACEBOOK:RECORD:WRITE:EXCEPTION",
75
+ type: "error",
76
+ sync_id: sync_config.sync_id,
77
+ sync_run_id: sync_config.sync_run_id
78
+ })
79
+ end
80
+
81
+ private
82
+
83
+ def generate_url(sync_config, connection_config)
84
+ sync_config.stream.url.gsub("{audience_id}", connection_config[:audience_id])
85
+ end
86
+
87
+ def create_payload(records, json_schema)
88
+ schema, data = extract_schema_and_data(records, json_schema)
89
+ {
90
+ "payload" => {
91
+ "schema" => schema,
92
+ "data" => data
93
+ }
94
+ }
95
+ end
96
+
97
+ def extract_schema_and_data(records, json_schema)
98
+ schema_properties = json_schema[:properties]
99
+ schema = records.first.keys.map(&:to_s).map(&:upcase)
100
+ data = []
101
+ records.each do |record|
102
+ encrypted_data_array = []
103
+ record.with_indifferent_access.each do |key, value|
104
+ schema_key = key.upcase
105
+ encrypted_value = schema_properties[schema_key] && schema_properties[schema_key]["x-hashRequired"] ? Digest::SHA256.hexdigest(value.to_s) : value
106
+ encrypted_data_array << encrypted_value
107
+ end
108
+ data << encrypted_data_array
109
+ end
110
+ [schema, data]
111
+ end
112
+
113
+ def ad_account_exists?(response, ad_account_id)
114
+ return if extract_data(response).any? { |ad_account| ad_account["id"] == "act_#{ad_account_id}" }
115
+
116
+ raise ArgumentError, "Ad account not found in business account"
117
+ end
118
+
119
+ def extract_data(response)
120
+ response_body = response.body
121
+ JSON.parse(response_body)["data"] if response_body
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,42 @@
1
+ {
2
+ "request_rate_limit": 600,
3
+ "request_rate_limit_unit": "minute",
4
+ "request_rate_concurrency": 10,
5
+ "streams": [
6
+ {
7
+ "name": "audience",
8
+ "action": "create",
9
+ "method": "POST",
10
+ "batch_support": true,
11
+ "batch_size": 10000,
12
+ "url": "https://graph.facebook.com/v18.0/{audience_id}/users",
13
+ "json_schema": {
14
+ "type": "object",
15
+ "additionalProperties": true,
16
+ "properties": {
17
+ "EMAIL": { "type": ["string", "null"], "default": null, "title": "Email", "x-hashRequired": true },
18
+ "PHONE": { "type": ["string", "null"], "default": null, "title": "Phone", "x-hashRequired": true },
19
+ "GEN": { "type": ["string", "null"], "default": null, "title": "Gender", "x-hashRequired": true },
20
+ "FI": { "type": ["string", "null"], "default": null, "title": "First Initial", "x-hashRequired": true },
21
+ "FN": { "type": ["string", "null"], "default": null, "title": "First Name", "x-hashRequired": true },
22
+ "DOBD": { "type": ["string", "null"], "default": null, "title": "Date of Birth (Day)", "x-hashRequired": true },
23
+ "DOBM": { "type": ["string", "null"], "default": null, "title": "Date of Birth (Month)", "x-hashRequired": true },
24
+ "DOBY": { "type": ["string", "null"], "default": null, "title": "Date of Birth (Year)", "x-hashRequired": true },
25
+ "LN": { "type": ["string", "null"], "default": null, "title": "Last Name", "x-hashRequired": true },
26
+ "CT": { "type": ["string", "null"], "default": null, "title": "City", "x-hashRequired": true },
27
+ "ST": { "type": ["string", "null"], "default": null, "title": "State", "x-hashRequired": true },
28
+ "ZIP": { "type": ["string", "null"], "default": null, "title": "Zip Code", "x-hashRequired": true },
29
+ "COUNTRY": { "type": ["string", "null"], "default": null, "title": "Country", "x-hashRequired": true },
30
+ "EXTERN_ID": { "type": ["string", "null"], "default": null, "title": "External ID", "x-hashRequired": false},
31
+ "LOOKALIKE_VALUE": { "type": ["number", "null"], "default": null, "title": "Lookalike Value", "x-hashRequired": false },
32
+ "MADID": { "type": ["string", "null"], "default": null, "title": "Mobile ID", "x-hashRequired": false },
33
+ "PAGEUID": { "type": ["string", "null"], "default": null, "title": "Page-Scoped ID", "x-hashRequired": false }
34
+ }
35
+ },
36
+ "supported_sync_modes": ["incremental"],
37
+ "source_defined_cursor": true,
38
+ "default_cursor_field": ["updated"],
39
+ "source_defined_primary_key": [["email"]]
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "data": {
3
+ "name": "FacebookCustomAudience",
4
+ "title": "Facebook Custom Audiences",
5
+ "connector_type": "destination",
6
+ "category": "Ad-Tech",
7
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/adtech/facebook-ads",
8
+ "github_issue_label": "destination-facebook",
9
+ "icon": "icon.svg",
10
+ "license": "MIT",
11
+ "release_stage": "alpha",
12
+ "support_level": "community",
13
+ "tags": ["language:ruby", "outhad"]
14
+ }
15
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/adtech/facebook-ads",
3
+ "stream_type": "static",
4
+ "connection_specification": {
5
+ "$schema": "http://json-schema.org/draft-07/schema#",
6
+ "title": "Facebook Custom Audiences",
7
+ "type": "object",
8
+ "required": ["access_token", "ad_account_id", "audience_id"],
9
+ "properties": {
10
+ "access_token": {
11
+ "type": "string",
12
+ "outhad_secret": true,
13
+ "title": "Access Token",
14
+ "order": 0
15
+ },
16
+ "ad_account_id": {
17
+ "type": "string",
18
+ "title": "Ad Account Id",
19
+ "order": 1
20
+ },
21
+ "audience_id": {
22
+ "type": "string",
23
+ "title": "Audience Id",
24
+ "order": 2
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,23 @@
1
+ <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1365.3333 1365.3333" height="1365.3333" width="1365.3333" xml:space="preserve" id="svg2" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
2
+ <metadata id="metadata8">
3
+ <rdf:RDF>
4
+ <cc:Work rdf:about="">
5
+ <dc:format>
6
+ image/svg+xml
7
+ </dc:format>
8
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage">
9
+ </dc:type>
10
+ </cc:Work>
11
+ </rdf:RDF>
12
+ </metadata>
13
+ <defs id="defs6">
14
+ </defs>
15
+ <g transform="matrix(1.3333333,0,0,-1.3333333,0,1365.3333)" id="g10">
16
+ <g transform="scale(0.1)" id="g12">
17
+ <path id="path14" style="fill:#1877f2;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 10240,5120 c 0,2827.7 -2292.3,5120 -5120,5120 C 2292.3,10240 0,7947.7 0,5120 0,2564.46 1872.31,446.301 4320,62.1992 V 3640 H 3020 v 1480 h 1300 v 1128 c 0,1283.2 764.38,1992 1933.9,1992 560.17,0 1146.1,-100 1146.1,-100 V 6880 H 6754.38 C 6118.35,6880 5920,6485.33 5920,6080.43 V 5120 H 7340 L 7113,3640 H 5920 V 62.1992 C 8367.69,446.301 10240,2564.46 10240,5120">
18
+ </path>
19
+ <path id="path16" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 7113,3640 227,1480 H 5920 v 960.43 c 0,404.9 198.35,799.57 834.38,799.57 H 7400 v 1260 c 0,0 -585.93,100 -1146.1,100 C 5084.38,8240 4320,7531.2 4320,6248 V 5120 H 3020 V 3640 H 4320 V 62.1992 C 4580.67,21.3008 4847.84,0 5120,0 c 272.16,0 539.33,21.3008 800,62.1992 V 3640 h 1193">
20
+ </path>
21
+ </g>
22
+ </g>
23
+ </svg>
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad
4
+ module Integrations
5
+ module Destination
6
+ module GoogleSheets
7
+ include Outhad::Integrations::Core
8
+
9
+ class Client < DestinationConnector
10
+ prepend Outhad::Integrations::Core::Fullrefresher
11
+ prepend Outhad::Integrations::Core::RateLimiter
12
+ MAX_CHUNK_SIZE = 10_000
13
+
14
+ def check_connection(connection_config)
15
+ connection_config = connection_config.with_indifferent_access
16
+ authorize_client(connection_config)
17
+ fetch_google_spread_sheets(connection_config)
18
+ success_status
19
+ rescue StandardError => e
20
+ failure_status(e)
21
+ end
22
+
23
+ def discover(connection_config)
24
+ connection_config = connection_config.with_indifferent_access
25
+ authorize_client(connection_config)
26
+ spreadsheets = fetch_google_spread_sheets(connection_config)
27
+ catalog = build_catalog_from_spreadsheets(spreadsheets, connection_config)
28
+ catalog.to_outhad_message
29
+ rescue StandardError => e
30
+ handle_exception(e, {
31
+ context: "GOOGLE_SHEETS:CRM:DISCOVER:EXCEPTION",
32
+ type: "error"
33
+ })
34
+ end
35
+
36
+ def write(sync_config, records, action = "create")
37
+ setup_write_environment(sync_config, action)
38
+ process_record_chunks(records, sync_config)
39
+ rescue StandardError => e
40
+ handle_exception(e, {
41
+ context: "GOOGLE_SHEETS:CRM:WRITE:EXCEPTION",
42
+ type: "error",
43
+ sync_id: sync_config.sync_id,
44
+ sync_run_id: sync_config.sync_run_id
45
+ })
46
+ end
47
+
48
+ def clear_all_records(sync_config)
49
+ setup_write_environment(sync_config, "clear")
50
+ connection_specification = sync_config.destination.connection_specification.with_indifferent_access
51
+ spreadsheet = fetch_google_spread_sheets(connection_specification)
52
+ sheet_ids = spreadsheet.sheets.map(&:properties).map(&:sheet_id)
53
+
54
+ delete_extra_sheets(sheet_ids)
55
+
56
+ unless sheet_ids.empty?
57
+ clear_response = clear_sheet_data(spreadsheet.sheets.first.properties.title)
58
+ return control_message("Successfully cleared data.", "succeeded") if clear_response&.cleared_range
59
+ end
60
+
61
+ control_message("Failed to clear data.", "failed")
62
+ rescue StandardError => e
63
+ control_message(e.message, "failed")
64
+ end
65
+
66
+ private
67
+
68
+ # To define the level of access granted to your app, you need to identify and declare authorization scopes which is provided by google scopse https://developers.google.com/sheets/api/scopes
69
+ def authorize_client(config)
70
+ credentials = config[:credentials_json]
71
+ @client = Google::Apis::SheetsV4::SheetsService.new
72
+ @client.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
73
+ json_key_io: StringIO.new(credentials.to_json),
74
+ scope: GOOGLE_SHEETS_SCOPE
75
+ )
76
+ end
77
+
78
+ # Extract spreadsheet id from the spreadsheet link and return the metadata for all the sheets
79
+ def fetch_google_spread_sheets(connection_config)
80
+ spreadsheet_id = extract_spreadsheet_id(connection_config[:spreadsheet_link])
81
+ @client.get_spreadsheet(spreadsheet_id)
82
+ end
83
+
84
+ # dynamically builds catalog based on spreadsheet metadata
85
+ def build_catalog_from_spreadsheets(spreadsheet, connection_config)
86
+ catalog = build_catalog(load_catalog)
87
+ @spreadsheet_id = extract_spreadsheet_id(connection_config[:spreadsheet_link])
88
+
89
+ spreadsheet.sheets.each do |sheet|
90
+ process_sheet_for_catalog(sheet, catalog)
91
+ end
92
+
93
+ catalog
94
+ end
95
+
96
+ # Builds catalog for the single spreadsheet based on column name
97
+ def process_sheet_for_catalog(sheet, catalog)
98
+ sheet_name, last_column_index = extract_sheet_properties(sheet)
99
+ column_names = fetch_column_names(sheet_name, last_column_index)
100
+ catalog.streams << generate_json_schema(column_names, sheet_name) if column_names
101
+ end
102
+
103
+ def extract_sheet_properties(sheet)
104
+ [sheet.properties.title, sheet.properties.grid_properties.column_count]
105
+ end
106
+
107
+ def fetch_column_names(sheet_name, last_column_index)
108
+ header_range = generate_header_range(sheet_name, last_column_index)
109
+ spread_sheet_value(header_range)&.flatten
110
+ end
111
+
112
+ def spread_sheet_value(header_range)
113
+ @spread_sheet_value ||= @client.get_spreadsheet_values(@spreadsheet_id, header_range).values
114
+ end
115
+
116
+ def generate_header_range(sheet_name, last_column_index)
117
+ "#{sheet_name}!A1:#{column_index_to_letter(last_column_index)}1"
118
+ end
119
+
120
+ def column_index_to_letter(index)
121
+ ("A".."ZZZ").to_a[index - 1]
122
+ end
123
+
124
+ def generate_json_schema(column_names, sheet_name)
125
+ {
126
+ name: sheet_name,
127
+ action: "create",
128
+ batch_support: true,
129
+ batch_size: 10_000,
130
+ json_schema: generate_properties_schema(column_names),
131
+ supported_sync_modes: %w[incremental full_refresh]
132
+ }.with_indifferent_access
133
+ end
134
+
135
+ def generate_properties_schema(column_names)
136
+ properties = column_names.each_with_object({}) do |field, props|
137
+ props[field] = { "type" => "string" }
138
+ end
139
+
140
+ { "$schema" => JSON_SCHEMA_URL, "type" => "object", "properties" => properties }
141
+ end
142
+
143
+ def setup_write_environment(sync_config, action)
144
+ @action = sync_config.stream.action || action
145
+ connection_specification = sync_config.destination.connection_specification.with_indifferent_access
146
+ @spreadsheet_id = extract_spreadsheet_id(connection_specification[:spreadsheet_link])
147
+ authorize_client(connection_specification)
148
+ end
149
+
150
+ def extract_spreadsheet_id(link)
151
+ link[GOOGLE_SPREADSHEET_ID_REGEX, 1] || link
152
+ end
153
+
154
+ # Batch has a limit of sending 2MB data. So creating a chunk of records to meet that limit
155
+ def process_record_chunks(records, sync_config)
156
+ log_message_array = []
157
+ write_success = 0
158
+ write_failure = 0
159
+
160
+ records.each_slice(MAX_CHUNK_SIZE) do |chunk|
161
+ values = prepare_chunk_values(chunk, sync_config.stream)
162
+ request, response = *update_sheet_values(values, sync_config.stream.name)
163
+ write_success += values.size
164
+ log_message_array << log_request_response("info", request, response)
165
+ rescue StandardError => e
166
+ handle_exception(e, {
167
+ context: "GOOGLE_SHEETS:RECORD:WRITE:EXCEPTION",
168
+ type: "error",
169
+ sync_id: sync_config.sync_id,
170
+ sync_run_id: sync_config.sync_run_id
171
+ })
172
+ write_failure += chunk.size
173
+ log_message_array << log_request_response("error", request, e.message)
174
+ end
175
+ tracking_message(write_success, write_failure, log_message_array)
176
+ end
177
+
178
+ # We need to format the data to adhere to google sheets API format. This converts the sync mapped data to 2D array format expected by google sheets API
179
+ def prepare_chunk_values(chunk, stream)
180
+ last_column_index = spread_sheet_value(stream.name).count
181
+ fields = fetch_column_names(stream.name, last_column_index)
182
+
183
+ chunk.map do |row|
184
+ row_values = Array.new(fields.size, nil)
185
+ row.each do |key, value|
186
+ index = fields.index(key.to_s)
187
+ row_values[index] = value if index
188
+ end
189
+ row_values
190
+ end
191
+ end
192
+
193
+ def update_sheet_values(values, stream_name)
194
+ row_count = spread_sheet_value(stream_name).count
195
+ range = "#{stream_name}!A#{row_count + 1}"
196
+ value_range = Google::Apis::SheetsV4::ValueRange.new(range: range, values: values)
197
+
198
+ batch_update_request = Google::Apis::SheetsV4::BatchUpdateValuesRequest.new(
199
+ value_input_option: "RAW",
200
+ data: [value_range]
201
+ )
202
+
203
+ # TODO: Remove & this is added for the test to pass we need
204
+ response = @client&.batch_update_values(@spreadsheet_id, batch_update_request)
205
+ [batch_update_request, response]
206
+ end
207
+
208
+ def load_catalog
209
+ read_json(CATALOG_SPEC_PATH)
210
+ end
211
+
212
+ def delete_extra_sheets(sheet_ids)
213
+ # Leave one sheet intact as a spreadsheet must have at least one sheet.
214
+ # Delete all other sheets.
215
+ (sheet_ids.length - 1).times do |i|
216
+ request = Google::Apis::SheetsV4::BatchUpdateSpreadsheetRequest.new(
217
+ requests: [{ delete_sheet: { sheet_id: sheet_ids[i + 1] } }]
218
+ )
219
+ @client.batch_update_spreadsheet(@spreadsheet_id, request)
220
+ end
221
+ end
222
+
223
+ def clear_sheet_data(sheet_title)
224
+ clear_request = Google::Apis::SheetsV4::ClearValuesRequest.new
225
+ @client&.clear_values(@spreadsheet_id, "#{sheet_title}!A2:Z", clear_request)
226
+ end
227
+
228
+ def control_message(message, status)
229
+ ControlMessage.new(
230
+ type: "full_refresh",
231
+ emitted_at: Time.now.to_i,
232
+ status: ConnectionStatusType[status],
233
+ meta: { detail: message }
234
+ ).to_outhad_message
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "request_rate_limit": 300,
3
+ "request_rate_limit_unit": "minute",
4
+ "request_rate_concurrency": 10,
5
+ "streams": []
6
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "data": {
3
+ "name": "GoogleSheets",
4
+ "title": "Google Sheets",
5
+ "connector_type": "destination",
6
+ "category": "Productivity Tools",
7
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/productivity-tools/google-sheets",
8
+ "github_issue_label": "destination-google-sheets",
9
+ "icon": "icon.svg",
10
+ "license": "MIT",
11
+ "release_stage": "alpha",
12
+ "support_level": "community",
13
+ "tags": ["language:ruby", "outhad"]
14
+ }
15
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/productivity-tools/google-sheets",
3
+ "stream_type": "dynamic",
4
+ "connection_specification": {
5
+ "$schema": "http://json-schema.org/draft-07/schema#",
6
+ "title": "Google Sheets",
7
+ "type": "object",
8
+ "required": ["credentials_json"],
9
+ "properties": {
10
+ "spreadsheet_link": {
11
+ "type": "string"
12
+ },
13
+ "credentials_json": {
14
+ "type": "object",
15
+ "description": "You can get the keys from the Google Cloud web console. First, go to the IAM page and select Service Accounts from the left menu. Next, locate your service account in the list, click on its Keys tab, and then click Add Key. Lastly, click Create new key and select JSON.",
16
+ "title": "",
17
+ "properties": {
18
+ "type": {
19
+ "type": "string",
20
+ "enum": ["service_account"]
21
+ },
22
+ "project_id": {
23
+ "type": "string"
24
+ },
25
+ "private_key_id": {
26
+ "type": "string"
27
+ },
28
+ "private_key": {
29
+ "type": "string",
30
+ "outhad_secret": true
31
+ },
32
+ "client_email": {
33
+ "type": "string",
34
+ "format": "email"
35
+ },
36
+ "client_id": {
37
+ "type": "string"
38
+ },
39
+ "auth_uri": {
40
+ "type": "string",
41
+ "format": "uri"
42
+ },
43
+ "token_uri": {
44
+ "type": "string",
45
+ "format": "uri"
46
+ },
47
+ "auth_provider_x509_cert_url": {
48
+ "type": "string",
49
+ "format": "uri"
50
+ },
51
+ "client_x509_cert_url": {
52
+ "type": "string",
53
+ "format": "uri"
54
+ },
55
+ "universe_domain": {
56
+ "type": "string"
57
+ }
58
+ },
59
+ "required": [
60
+ "type",
61
+ "project_id",
62
+ "private_key_id",
63
+ "private_key",
64
+ "client_email",
65
+ "client_id",
66
+ "auth_uri",
67
+ "token_uri",
68
+ "auth_provider_x509_cert_url",
69
+ "client_x509_cert_url",
70
+ "universe_domain"
71
+ ]
72
+ }
73
+ }
74
+ }
75
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 242423 333333" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"><defs><mask id="c"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="200294" y1="91174.8" x2="200294" y2="176113"><stop offset="0" stop-opacity=".02" stop-color="#fff"/><stop offset="1" stop-opacity=".2" stop-color="#fff"/></linearGradient><path fill="url(#a)" d="M158015 84111h84558v99065h-84558z"/></mask><mask id="e"><radialGradient id="b" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="0" fx="0" fy="0"><stop offset="0" stop-opacity="0" stop-color="#fff"/><stop offset="1" stop-opacity=".098" stop-color="#fff"/></radialGradient><path fill="url(#b)" d="M-150-150h242723v333633H-150z"/></mask><radialGradient id="f" gradientUnits="userSpaceOnUse" cx="9696.85" cy="10000.4" r="166667" fx="9696.85" fy="10000.4"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#fff"/></radialGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="200294" y1="95125.2" x2="200294" y2="172162"><stop offset="0" stop-color="#263138"/><stop offset="1" stop-color="#263138"/></linearGradient></defs><g fill-rule="nonzero"><path d="M151513 0H22729C10227 0 1 10227 1 22728v287877c0 12505 10227 22728 22728 22728h196966c12505 0 22728-10224 22728-22728V90911l-53028-37880L151513 0z" fill="#0f9c57"/><path d="M60606 162880v109853h121216V162880H60606zm53032 94698H75757v-18938h37881v18938zm0-30301H75757v-18946h37881v18946zm0-30310H75757v-18936h37881v18936zm53030 60611h-37884v-18938h37884v18938zm0-30301h-37884v-18946h37884v18946zm0-30310h-37884v-18936h37884v18936z" fill="#f0f0f0"/><path mask="url(#c)" fill="url(#d)" d="M158165 84261l84258 84245V90911z"/><path d="M151513 0v68184c0 12557 10173 22727 22727 22727h68183L151513 0z" fill="#87cdac"/><path d="M22728 0C10226 0 0 10227 0 22729v1893C0 12123 10227 1894 22728 1894h128784V1H22728z" fill="#fff" fill-opacity=".2"/><path d="M219694 331443H22728C10226 331443 0 321213 0 308715v1890c0 12505 10227 22728 22728 22728h196966c12505 0 22728-10224 22728-22728v-1890c0 12499-10224 22728-22728 22728z" fill="#263138" fill-opacity=".2"/><path d="M174239 90911c-12554 0-22727-10170-22727-22727v1893c0 12557 10173 22727 22727 22727h68183v-1893h-68183z" fill="#263138" fill-opacity=".102"/><path d="M151513 0H22729C10227 0 1 10227 1 22729v287876c0 12505 10227 22728 22728 22728h196966c12505 0 22728-10224 22728-22728V90911L151513 0z" mask="url(#e)" fill="url(#f)"/></g></svg>