<commit_before>// Copyright 2014 The Rector & Visitors of the University of Virginia
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using Syncfusion.SfChart.XForms;
using System.Collections.Generic;
using Microsoft.AppCenter.Analytics;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Reflection;

namespace Sensus.Probes.User.Scripts
{
    /// <summary>
    /// The Script Probe allows Sensus to deliver custom surveys to the user in response to either a schedule or the data coming off other probes. For 
    /// example, one could configure a survey to display at particular times or randomly within particular time blocks. One could also configure a survey 
    /// to display when a <see cref="Datum"/> from another probe meets particular criteria.
    /// </summary>
    public class ScriptProbe : Probe
    {

        // android allows us to dynamically load code assemblies, but iOS does not. so, the current approach
        // is to only support dynamic loading on android and force compile-time assembly inclusion on ios.
#if __ANDROID__

        public static IScriptProbeAgent GetAgent(byte[] assemblyBytes, string agentId)
        {
            return GetAgents(assemblyBytes).SingleOrDefault(agent => agent.Id == agentId);
        }

        public static List<IScriptProbeAgent> GetAgents(byte[] assemblyBytes)
        {
            return Assembly.Load(assemblyBytes)
                           .GetTypes()
                           .Where(t => !t.IsAbstract && t.GetInterfaces().Contains(typeof(IScriptProbeAgent)))
                           .Select(Activator.CreateInstance)
                           .Cast<IScriptProbeAgent>()
                           .ToList();
        }

        /// <summary>
        /// Bytes of the assembly in which the <see cref="Agent"/> is contained.
        /// </summary>
        /// <value>The agent assembly bytes.</value>
        public byte[] AgentAssemblyBytes { get; set; }

#elif __IOS__

        public static IScriptProbeAgent GetAgent(string agentId)
        {
            return GetAgents().SingleOrDefault(agent => agent.Id == agentId);
        }

        public static List<IScriptProbeAgent> GetAgents()
        {
            // get agents from the current assembly. they must be linked at compile time.
            return Assembly.GetAssembly(typeof(ExampleScriptProbeAgent.ExampleRandomScriptProbeAgent))
                           .GetTypes()
                           .Where(t => !t.IsAbstract && t.GetInterfaces().Contains(typeof(IScriptProbeAgent)))
                           .Select(Activator.CreateInstance)
                           .Cast<IScriptProbeAgent>()
                           .ToList();
        }

#endif

        private ObservableCollection<ScriptRunner> _scriptRunners;
        private IScriptProbeAgent _agent;

        /// <summary>
        /// Gets or sets the agent that controls survey delivery. See [here](xref:adaptive_surveys) for more information.
        /// </summary>
        /// <value>The agent.</value>
        [JsonIgnore]
        public IScriptProbeAgent Agent
        {
            get
            {
                // attempt to lazy-load the agent if there is none
                if (_agent == null)
                {
                    try
                    {
#if __ANDROID__
                        _agent = GetAgent(AgentAssemblyBytes, AgentId);
#elif __IOS__
                        _agent = GetAgent(AgentId);
#endif

                        // set the agent's policy if we previously received one (e.g., via push notification)
                        if (!string.IsNullOrWhiteSpace(AgentPolicyJSON))
                        {
                            _agent.SetPolicy(AgentPolicyJSON);
                        }
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get()?.Logger.Log("Exception while loading agent:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }<commit_msg>Agent load.<commit_after>// Copyright 2014 The Rector & Visitors of the University of Virginia
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;
using Syncfusion.SfChart.XForms;
using System.Collections.Generic;
using Microsoft.AppCenter.Analytics;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Reflection;

namespace Sensus.Probes.User.Scripts
{
    /// <summary>
    /// The Script Probe allows Sensus to deliver custom surveys to the user in response to either a schedule or the data coming off other probes. For 
    /// example, one could configure a survey to display at particular times or randomly within particular time blocks. One could also configure a survey 
    /// to display when a <see cref="Datum"/> from another probe meets particular criteria.
    /// </summary>
    public class ScriptProbe : Probe
    {

        // android allows us to dynamically load code assemblies, but iOS does not. so, the current approach
        // is to only support dynamic loading on android and force compile-time assembly inclusion on ios.
#if __ANDROID__

        public static IScriptProbeAgent GetAgent(byte[] assemblyBytes, string agentId)
        {
            return GetAgents(assemblyBytes).SingleOrDefault(agent => agent.Id == agentId);
        }

        public static List<IScriptProbeAgent> GetAgents(byte[] assemblyBytes)
        {
            return Assembly.Load(assemblyBytes)
                           .GetTypes()
                           .Where(t => !t.IsAbstract && t.GetInterfaces().Contains(typeof(IScriptProbeAgent)))
                           .Select(Activator.CreateInstance)
                           .Cast<IScriptProbeAgent>()
                           .ToList();
        }

        /// <summary>
        /// Bytes of the assembly in which the <see cref="Agent"/> is contained.
        /// </summary>
        /// <value>The agent assembly bytes.</value>
        public byte[] AgentAssemblyBytes { get; set; }

#elif __IOS__

        public static IScriptProbeAgent GetAgent(string agentId)
        {
            return GetAgents().SingleOrDefault(agent => agent.Id == agentId);
        }

        public static List<IScriptProbeAgent> GetAgents()
        {
            // get agents from the current assembly. they must be linked at compile time.
            return Assembly.GetAssembly(typeof(ExampleScriptProbeAgent.ExampleRandomScriptProbeAgent))
                           .GetTypes()
                           .Where(t => !t.IsAbstract && t.GetInterfaces().Contains(typeof(IScriptProbeAgent)))
                           .Select(Activator.CreateInstance)
                           .Cast<IScriptProbeAgent>()
                           .ToList();
        }

#endif

        private ObservableCollection<ScriptRunner> _scriptRunners;
        private IScriptProbeAgent _agent;

        /// <summary>
        /// Gets or sets the agent that controls survey delivery. See [here](xref:adaptive_surveys) for more information.
        /// </summary>
        /// <value>The agent.</value>
        [JsonIgnore]
        public IScriptProbeAgent Agent
        {
            get
            {
                // attempt to lazy-load the agent if there is none and we an agent id
                if (_agent == null && !string.IsNullOrWhiteSpace(AgentId))
                {
                    try
                    {
#if __ANDROID__
                        // also require an assembly on android, which is where we get the agents from.
                        if (AgentAssemblyBytes != null)
                        {
                            _agent = GetAgent(AgentAssemblyBytes, AgentId);
                        }
#elif __IOS__
                        // there is no assembly in ios per apple restrictions on dynamically loaded code. agents are baked into the app instead.
                        _agent = GetAgent(AgentId);
#endif

                        // set the agent's policy if we previously received one (e.g., via push notification)
                        if (!string.IsNullOrWhiteSpace(AgentPolicyJSON))
                        {
                            _agent.SetPolicy(AgentPolicyJSON);
                        }
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get()?.Logger.Log("Exception while loading agent:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
{'fraction_non_alphanumeric': 0.08314491264131552, 'fraction_numerical': 0.001644398766700925, 'mean_word_length': 1.8892517814726841, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3426924', 'n_tokens_mistral': 2362, 'n_tokens_neox': 2281, 'n_words': 796}