text:
layout: page
title: About me
tags: [about, Jekyll, theme, moon]
date: 2016-03-21
---

Welcome to my blog

## Short bio
I am an Android developer and the past year I am developing Android applications, using mostly Java on Android Studio but also having a little experience developing with C# on Xamarin for Visual studio. I am currently learning about technologies and practices that make developing with Java and Android easier, more structured, easily scalable and producing better quality code.
I have also worked with ASP .NET and MVC5 creating simple web applications.

I am a jack of many trades, I have a strong background on IT, computer hardware and networks with many years of experience, I am a graduate of Technological and Educational Institute of Thessaly, Department of Computer Science and Telecommunications (CST), and I also enjoy getting my hands on technologies involving sensors, micro-controllers and small electronics like Arduino and embedded systems like Raspberry Pi, building small projects for the purpose of discovering the IOT world and gaining experience at working with Linux.

I am a part of a team of developers and a co-founder Figata, a startup emerging from the 1st Startup Weekend Larisa as the 1st place winners.

## Find me
Chechout my github at https://github.com/chronvas
contact me via Linked-In linkedin.com/in/chronvas

redpajama_set_name: RedPajamaGithub


text:
using Papper.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Linq;

namespace Papper.Types
{
    internal abstract class PlcObject : PlcMetaDataTreeNode, IPlcObject
    {
        public string? Selector { get; set; }
        public Type? ElemenType { get; set; }
        public bool AllowOddByteOffsetInArray { get; set; }

        public PlcSize Offset { get; } = new PlcSize();

        public virtual bool HasReadOnlyChilds { get; internal set; }
        public virtual bool HasNotAccessibleChilds { get; internal set; }
        public virtual bool HasRootAccessNotAllowedChilds { get; internal set; }
        public virtual bool IsReadOnly { get; internal set; }
        public virtual bool IsNotAccessible { get; internal set; }
        public virtual int? ArrayStartIndex { get; internal set; }
        public virtual bool RootAccessNotAllowed { get; internal set; }

        public virtual int ByteOffset => Offset.Bytes;
        public virtual int BitOffset => Offset.Bits;
        public virtual int ByteSize => Size == null ? 0 : Size.Bytes;
        public virtual int BitSize => Size == null ? 0 : Size.Bits;

        public abstract Type DotNetType { get; }

        public IEnumerable<IPlcObject> ChildVars => Childs.OfType<IPlcObject>();

        public virtual PlcSize? Size { get; protected set; }

        public static PlcObject? AddPlcObjectToTree(PlcObject obj, ITree tree, ITreePath path)
        {
            var node = PlcMetaDataTreePath.CreateNodePath(path, obj);
            if (node == null)
            {
                return null;
            }

            if (tree.Get(node) is not PlcObject metaDataNode)
            {
                lock (tree.Root)
                {
                    if (tree.Get(node) is PlcObject plcObj)
                    {
                        return plcObj;
                    }

                    tree.Root.AddChild(path, obj);
                }
                return obj;
            }
            return metaDataNode;
        }

        protected PlcObject(string name)
            : base(name)
        {
        }

        public override string ToString() => GetType().ToString();

        public abstract object ConvertFromRaw(PlcObjectBinding plcObjectBinding, Span<byte> data);
        public abstract void ConvertToRaw(object value, PlcObjectBinding plcObjectBinding, Span<byte> data);

        public virtual object? StringToObject(string value)
        {
            try
            {
                var type = PlcObjectFactory.GetTypeForPlcObject(GetType());
                return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
            }
            catch
            { }
            return null;
        }

        public virtual bool AreDataEqual(object obj1, object obj2)
        {
            var t1 = obj1.GetType();
            var t2 = obj2.GetType();

            if (t1 == t2) { return t1 != typeof(ExpandoObject) ? ElementEqual(obj1, obj2) : DynamicObjectCompare(obj1, obj2); }
            try { return ElementEqual(obj1, Convert.ChangeType(obj2, t1, CultureInfo.InvariantCulture)); } catch { }
            return false;
        }

        private bool ElementEqual(object obj1, object obj2)
        {
            if (obj1 is IEnumerable list1 && obj2 is IEnumerable list2)
            {
                var enumerator1 = list1.GetEnumerator();
                var enumerator2 = list2.GetEnumerator();
                while (true)
                {
                    var e1 = enumerator1.MoveNext();
                    var e2 = enumerator2.MoveNext();
                    if (e1 && e2)
                    {
                        if (!AreDataEqual(enumerator1.Current, enumerator2.Current))
                        {
                            return false;
                        }
                    }
                    else
                    {
                        return e1 == e2; //Length not the same?
                    }
                }
            }
            return obj1.Equals(obj2);
        }

        private bool DynamicObjectCompare(object obj1, object obj2)
        {

            if (obj1 is IDictionary<string, object> dictionary1 && obj2 is IDictionary<string, object> dictionary2)
            {
                foreach (var o1 in dictionary1)
                {
                    if (!dictionary2.TryGetValue(o1.Key, out var o2) || !AreDataEqual(o1.Value, o2))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

    }
}


text:
import Ember from 'ember';
const { inject } = Ember;

export default Ember.Route.extend({
  bodyClass: 'bg-primary',
  favoriteStops: inject.service(),

  setupController(controller, model) {
    this._super(controller, model);
    let favoriteStops = this.get('favoriteStops');
    controller.set('favoriteStops', favoriteStops);
  },

  actions: {
    reorderFavorites(favorites) {
       this.get('favoriteStops').replaceStops(favorites);
    }
  }
});


text:
/**
 * Created by Matt on 12/2/2016.
 */

app.factory('AuthService', function ($rootScope, GameListenerService) {
    'use strict';

    var GameListenerServicerKey;

    var authedUser = null;

    var authenticationListenerManager = new ListenerManager();
    var currentlyPlayingListenerManager = new ListenerManager();

    var currentlyPlayingSteamId = null;

    GameListenerServicerKey = GameListenerService.addOnUpdateListener(function (packet) {
        if (packet.provider &&
            packet.provider.steamid != null ) {

            if(packet.provider.steamid != currentlyPlayingSteamId) {
                setCurrentlyPlayingSteamId(packet.provider.steamid);
            }
            return;
        }
        setCurrentlyPlayingSteamId(null);
    });

    function getCurrentPlayer(){
        return currentlyPlayingSteamId;
    }

    function setCurrentlyPlayingSteamId(steamId){
        currentlyPlayingSteamId = steamId;
        currentlyPlayingListenerManager.notifyListenersWithObject(currentlyPlayingSteamId);
    }

    function setAuthedUser(PlayerDetails){
        authedUser = PlayerDetails;
        authenticationListenerManager.notifyListeners();
    }

    /*
     * Public
     * @return boolean Whether there is a currently authed user
     */
    function isAuthenticated() {
        return authedUser != null;
    }

    /*
     * Public
     * @return string SteamId of currently authed user
     */
    function getAuthedUser(){
        return authedUser;
    }

    function addAutheticationChangedListener(listenerFunction){
        return authenticationListenerManager.addListener(listenerFunction);
    }

    function addCurrentUserChangedListener(listenerFunction){
        return currentlyPlayingListenerManager.addListener(listenerFunction);
    }

    return {
        getCurrentPlayer: getCurrentPlayer,
        isAuthenticated: isAuthenticated,
        setAuthedUser: setAuthedUser,
        getAuthedUser: getAuthedUser,
        addAutheticationChangedListener: addAutheticationChangedListener,
        addCurrentUserChangedListener: addCurrentUserChangedListener
    };
});


text:
package rsc.publisher;

import java.util.Objects;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import rsc.flow.Loopback;
import rsc.subscriber.MultiSubscriptionSubscriber;

/**
 * Switches to another source if the first source turns out to be empty.
 *
 * @param <T> the value type
 */
public final class PublisherSwitchIfEmpty<T> extends PublisherSource<T, T> {

    final Publisher<? extends T> other;

    public PublisherSwitchIfEmpty(Publisher<? extends T> source, Publisher<? extends T> other) {
        super(source);
        this.other = Objects.requireNonNull(other, "other");
    }

    @Override
    public void subscribe(Subscriber<? super T> s) {
        PublisherSwitchIfEmptySubscriber<T> parent = new PublisherSwitchIfEmptySubscriber<>(s, other);

        s.onSubscribe(parent);

        source.subscribe(parent);
    }

    static final class PublisherSwitchIfEmptySubscriber<T> extends MultiSubscriptionSubscriber<T, T>
            implements Loopback {

        final Publisher<? extends T> other;

        boolean once;

        public PublisherSwitchIfEmptySubscriber(Subscriber<? super T> actual, Publisher<? extends T> other) {
            super(actual);
            this.other = other;
        }

        @Override
        public void onNext(T t) {
            if (!once) {
                once = true;
            }

            subscriber.onNext(t);
        }

        @Override
        public void onComplete() {
            if (!once) {
                once = true;

                other.subscribe(this);
            } else {
                subscriber.onComplete();
            }
        }

        @Override
        public Object connectedInput() {
            return null;
        }

        @Override
        public Object connectedOutput() {
            return other;
        }
    }
}


text:
Validate form asynchronous. A variation of https://github.com/freeformsystems/async-validate

[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![gemnasium deps][gemnasium-image]][gemnasium-url]
[![node version][node-image]][node-url]
[![npm download][download-image]][download-url]

[npm-image]: http://img.shields.io/npm/v/async-validator.svg?style=flat-square
[npm-url]: http://npmjs.org/package/async-validator
[travis-image]: https://img.shields.io/travis/yiminghe/async-validator.svg?style=flat-square
[travis-url]: https://travis-ci.org/yiminghe/async-validator
[coveralls-image]: https://img.shields.io/coveralls/yiminghe/async-validator.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/yiminghe/async-validator?branch=master
[gemnasium-image]: http://img.shields.io/gemnasium/yiminghe/async-validator.svg?style=flat-square
[gemnasium-url]: https://gemnasium.com/yiminghe/async-validator
[node-image]: https://img.shields.io/badge/node.js-%3E=4.0.0-green.svg?style=flat-square
[node-url]: http://nodejs.org/download/
[download-image]: https://img.shields.io/npm/dm/async-validator.svg?style=flat-square
[download-url]: https://npmjs.org/package/async-validator

## API

The following is modified from earlier version of [async-validate](https://github.com/freeformsystems/async-validate).

### Usage

Basic usage involves defining a descriptor, assigning it to a schema and passing the object to be validated and a callback function to the `validate` method of the schema:

```javascript
var schema = require('async-validator');
var descriptor = {
  name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({name: "muji"}, (errors, fields) => {
  if(errors) {
    // validation failed, errors is an array of all errors
    // fields is an object keyed by field name with an array of
    // errors per field
    return handleErrors(errors, fields);
  }
  // validation passed
});
```

### Validate

```javascript
function(source, [options], callback)
```

* `source`: The object to validate (required).
* `options`: An object describing processing options for the validation (optional).
* `callback`: A callback function to invoke when validation completes (required).

### Options

* `first`: Boolean, Invoke `callback` when the first validation rule generates an error,
no more validation rules are processed.
If your validation involves multiple asynchronous calls (for example, database queries) and you only need the first error use this option.

* `firstFields`: Boolean|String[], Invoke `callback` when the first validation rule of the specified field generates an error,
no more validation rules of the same field are processed.  `true` means all fields.

### Rules

Rules may be functions that perform validation.

```javascript
function(rule, value, callback, source, options)
```

* `rule`: The validation rule in the source descriptor that corresponds to the field name being validated. It is always assigned a `field` property with the name of the field being validated.
* `value`: The value of the source object property being validated.
* `callback`: A callback function to invoke once validation is complete. It expects to be passed an array of `Error` instances to indicate validation failure.
* `source`: The source object that was passed to the `validate` method.
* `options`: Additional options.
* `options.messages`: The object containing validation error messages, will be deep merged with defaultMessages.

The options passed to `validate` are passed on to the validation functions so that you may reference transient data (such as model references) in validation functions. However, some option names are reserved; if you use these properties of the options object they are overwritten. The reserved properties are `messages`, `exception` and `error`.

```javascript
var schema = require('async-validator');
var descriptor = {
  name(rule, value, callback, source, options) {
    var errors = [];
    if(!/^[a-z0-9]+$/.test(value)) {
      errors.push(
        new Error(
          util.format("%s must be lowercase alphanumeric characters",
            rule.field)));
    }
    callback(errors);
  }
}
var validator = new schema(descriptor);
validator.validate({name: "Firstname"}, (errors, fields) => {
  if(errors) {
    return handleErrors(errors, fields);
  }
  // validation passed
});
```

It is often useful to test against multiple validation rules for a single field, to do so make the rule an array of objects, for example:

```javascript
var descriptor = {
  email: [
    {type: "string", required: true, pattern: schema.pattern.email},
    {validator(rule, value, callback, source, options) {
      var errors = [];
      // test if email address already exists in a database
      // and add a validation error to the errors array if it does
      callback(errors);
    }}
  ]
}
```

#### Type

Indicates the `type` of validator to use. Recognised type values are:

* `string`: Must be of type `string`. `This is the default type.`
* `number`: Must be of type `number`.
* `boolean`: Must be of type `boolean`.
* `method`: Must be of type `function`.
* `regexp`: Must be an instance of `RegExp` or a string that does not generate an exception when creating a new `RegExp`.
* `integer`: Must be of type `number` and an integer.
* `float`: Must be of type `number` and a floating point number.
* `array`: Must be an array as determined by `Array.isArray`.
* `object`: Must be of type `object` and not `Array.isArray`.
* `enum`: Value must exist in the `enum`.
* `date`: Value must be valid as determined by `Date`
* `url`: Must be of type `url`.
* `hex`: Must be of type `hex`.
* `email`: Must be of type `email`.

#### Required

The `required` rule property indicates that the field must exist on the source object being validated.

#### Pattern

The `pattern` rule property indicates a regular expression that the value must match to pass validation.

#### Range

A range is defined using the `min` and `max` properties. For `string` and `array` types comparison is performed against the `length`, for `number` types the number must not be less than `min` nor greater than `max`.

#### Length

To validate an exact length of a field specify the `len` property. For `string` and `array` types comparison is performed on the `length` property, for the `number` type this property indicates an exact match for the `number`, ie, it may only be strictly equal to `len`.

If the `len` property is combined with the `min` and `max` range properties, `len` takes precedence.

#### Enumerable

To validate a value from a list of possible values use the `enum` type with a `enum` property listing the valid values for the field, for example:

```javascript
var descriptor = {
  role: {type: "enum", enum: ['admin', 'user', 'guest']}
}
```

#### Whitespace

It is typical to treat required fields that only contain whitespace as errors. To add an additional test for a string that consists solely of whitespace add a `whitespace` property to a rule with a value of `true`. The rule must be a `string` type.

You may wish to sanitize user input instead of testing for whitespace, see [transform](#transform) for an example that would allow you to strip whitespace.

#### Deep Rules

If you need to validate deep object properties you may do so for validation rules that are of the `object` or `array` type by assigning nested rules to a `fields` property of the rule.

```javascript
var descriptor = {
  address: {
    type: "object", required: true,
    fields: {
      street: {type: "string", required: true},
      city: {type: "string", required: true},
      zip: {type: "string", required: true, len: 8, message: "invalid zip"}
    }
  },
  name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({ address: {} }, (errors, fields) => {
  // errors for street, address.city, address.zip and address.name
});
```

Note that if you do not specify the `required` property on the parent rule it is perfectly valid for the field not to be declared on the source object and the deep validation rules will not be executed as there is nothing to validate against.

Deep rule validation creates a schema for the nested rules so you can also specify the `options` passed to the `schema.validate()` method.

```javascript
var descriptor = {
  address: {
    type: "object", required: true, options: {single: true, first: true},
    fields: {
      street: {type: "string", required: true},
      city: {type: "string", required: true},
      zip: {type: "string", required: true, len: 8, message: "invalid zip"}
    }
  },
  name: {type: "string", required: true}
}
var validator = new schema(descriptor);
validator.validate({ address: {} }, (errors, fields) => {
  // now only errors for street and name
});
```

The parent rule is also validated so if you have a set of rules such as:

```javascript
var descriptor = {
  roles: {
    type: "array", required: true, len: 3,
    fields: {
      0: {type: "string", required: true},
      1: {type: "string", required: true},
      2: {type: "string", required: true}
    }
  }
}
```

And supply a source object of `{roles: ["admin", "user"]}` then two errors will be created. One for the array length mismatch and one for the missing required array entry at index 2.

#### defaultField

The `defaultField` property can be used with the `array` or `object` type for validating all values of the container.
It may be an `object` or `array` containing validation rules. For example:

```javascript
var descriptor = {
  urls: {
    type: "array", required: true,
    defaultField: {type: "url"}
  }
}
```

Note that `defaultField` is expanded to `fields`, see [deep rules](#deep-rules).

#### Transform

Sometimes it is necessary to transform a value before validation, possibly to coerce the value or to sanitize it in some way. To do this add a `transform` function to the validation rule. The property is transformed prior to validation and re-assigned to the source object to mutate the value of the property in place.

```javascript
var schema = require('async-validator');
var sanitize = require('validator').sanitize;
var descriptor = {
  name: {
    type: "string",
    required: true, pattern: /^[a-z]+$/,
    transform(value) {
      return sanitize(value).trim();
    }
  }
}
var validator = new schema(descriptor);
var source = {name: " user  "};
validator.validate(source, (errors, fields) => {
  assert.equal(source.name, "user");
});
```

Without the `transform` function validation would fail due to the pattern not matching as the input contains leading and trailing whitespace, but by adding the transform function validation passes and the field value is sanitized at the same time.

### Messages

Depending upon your application requirements, you may need i18n support or you may prefer different validation error messages.

The easiest way to achieve this is to assign a `message` to a rule:

```javascript
{name:{type: "string", required: true, message: "Name is required"}}
```

Message can be any type, such as jsx format.

```javascript
{name:{type: "string", required: true, message: <b>Name is required</b>}}
```

Potentially you may require the same schema validation rules for different languages, in which case duplicating the schema rules for each language does not make sense.

In this scenario you could just provide your own messages for the language and assign it to the schema:

```javascript
var schema = require('async-validator');
var cn = {
  required: '%s 必填',
};
var descriptor = {name:{type: "string", required: true}};
var validator = new schema(descriptor);
// deep merge with defaultMessages
validator.messages(cn);
...
```

If you are defining your own validation functions it is better practice to assign the message strings to a messages object and then access the messages via the `options.messages` property within the validation function.

### validator

you can custom validate function for specified field:

```js
{
  asyncField:{
    validator(rule,value,callback){
      ajax({
        url:'xx',
        value:value
      }).then(function(data){
        callback();
      },function(error){
        callback(new Error(error))
      });
    }
  }
}
```

## Test Case

```
npm test
npm run chrome-test
```

## Coverage

```
npm run coverage
```

open coverage/ dir

## License

Everything is [MIT](http://en.wikipedia.org/wiki/MIT_License).


text:
<!DOCTYPE html>

	<title>

            Agentic Communications, Inc. -

    Complete profile - Canadian Company Capabilities - Industries and Business - Industry Canada
  </title>

<meta charset="utf-8" />
<meta name="dcterms.language" title="ISO639-2" content="eng" />
<meta name="dcterms.title" content="" />
<meta name="description" content="" />
<meta name="dcterms.description" content="" />
<meta name="dcterms.type" content="report, data set" />
<meta name="dcterms.subject" content="businesses, industry" />
<meta name="dcterms.subject" content="businesses, industry" />
<meta name="dcterms.issued" title="W3CDTF" content="" />
<meta name="dcterms.modified" title="W3CDTF" content="" />
<meta name="keywords" content="" />

<meta name="dcterms.creator" content="" />
<meta name="author" content="" />
<meta name="dcterms.created" title="W3CDTF" content="" />
<meta name="dcterms.publisher" content="" />
<meta name="dcterms.audience" title="icaudience" content="" />
<meta name="dcterms.spatial" title="ISO3166-1" content="" />
<meta name="dcterms.spatial" title="gcgeonames" content="" />
<meta name="dcterms.format" content="HTML" />
<meta name="dcterms.identifier" title="ICsiteProduct" content="536" />

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta content="width=device-width,initial-scale=1" name="viewport">

<meta name = "format-detection" content = "telephone=no">

<meta name="robots" content="noarchive">

<link href="/utils/scripts/_WET_4-0/apps/themes-dist/gcweb/assets/favicon.ico" rel="icon" type="image/x-icon">
<link rel="stylesheet" href="/utils/scripts/_WET_4-0/apps/themes-dist/gcweb/css/wet-boew.min.css">

<link rel="stylesheet" href="/utils/scripts/_WET_4-0/apps/themes-dist/gcweb/css/theme.min.css">

<link rel="stylesheet" href="/utils/scripts/_WET_4-0/apps/themes-dist/gcweb/css/noscript.min.css" />

<link rel="stylesheet" href="/eic/home.nsf/css/add_WET_4-0_Canada_Apps.css">

  	<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
  	<link href="/app/ccc/srch/css/print.css" media="print" rel="stylesheet" type="text/css" />

<meta property="legalName" content="Department_of_Industry">

Skip to main content

Skip to "About this site"

Language selection

Français

<object type="image/svg+xml" tabindex="-1" data="/utils/scripts/_WET_4-0/apps/themes-dist/gcweb/assets/sig-blk-en.svg"></object> Government of Canada

Search and menus

Search and menus

Topics menu

Jobs

Immigration

Travel

Business

Benefits

Health

Taxes

More services

You are here:

Home

Industries and Business

Canadian Company Capabilities

<input id="showMore" type="hidden" value='more'/>
<input id="showLess" type="hidden" value='less'/>

 Company profile - Canadian Company Capabilities

New Search |

<form name="searchForm" method="post" action="/app/ccc/srch/bscSrch.do">

          <input type="hidden" name="lang" value="eng" />
          <input type="hidden" name="profileId" value="" />
          <input type="hidden" name="prtl" value="1" />
          <input type="hidden" name="searchPage" value="%2Fapp%2Fccc%2Fsrch%2FcccBscSrch.do%3Flang%3Deng%26amp%3Bprtl%3D1%26amp%3Btagid%3D"  />

          <input type="hidden" name="V_SEARCH.scopeCategory" value="CCC.Root" />

          <input type="hidden" name="V_SEARCH.depth" value="1" />
          <input type="hidden" name="V_SEARCH.showStricts" value="false" />
          <input id="repeatSearchBtn" class="btn btn-link" type="submit" value="Return to search results" />

  </form>

| Previous Company

| Next Company

      Third-Party Information Liability Disclaimer

Some of the information on this Web page has been provided by external sources. The Government of Canada is not responsible for the accuracy, reliability or currency of the information supplied by external sources. Users wishing to rely upon this information should consult directly with the source of the information. Content provided by external sources is not subject to official languages, privacy and accessibility requirements.

      Agentic Communications, Inc.

Legal/Operating Name:

Agentic Communications, Inc.

http://www.agentic.ca

agentic-info@agentic.ca

Mailing Address:

              	<address class="mrgn-bttm-md">

                   701-207 Hastings St W

                    VANCOUVER,

                    British Columbia

                  V6B 1H7

                </address>

Location Address:

              	         <address class="mrgn-bttm-md">

                   701-207 Hastings St W

                    VANCOUVER,

                    British Columbia

                  V6B 1H7

                         </address>

Tel.:
		      (604) 255-2131

Fax:
		      (604) 255-2505

Logo

Company Profile

            Agentic delivers innovative and impactful creative digital media campaigns in support of the online presence of our social change clients, such as medium to large not-for-profits, social venture, and CSR organizations to grow and engage their constituents.

We have the skills, tools, and experience, and the commitment to service excellence, to assist organizations to better serve their communities, constituents, and customers online.

Led by Founder and President Phillip Djwa, Agentic works with medium to large companies and agencies to plan and deliver strategic, integrated web development systems and solutions. And we meticulously manage the process from initial consultation to final analysis and feedback.

				Full profile

				Full profile

				Contact information

                Phillip
                Djwa

                  Title:

                President

                    Area of Responsibility:

                    Management Executive.

                  Telephone:

                (604) 255-2131

                  Ext:

                101

                  Facsimile:

                (604) 255-2505

                    Email:

                  agentic-info@agentic.ca

  top of page

				Company description

            Country of Ownership:

              Canada

              Year Established:

            2000

            Exporting:

              Yes

                Primary Industry (NAICS):

				541510 - Computer Systems Design and Related Services

            Alternate Industries (NAICS):

            519130 - Internet Publishing and Broadcasting, and Web Search Portals

            541910 - Marketing Research and Public Opinion Polling

            Primary Business Activity:

            Services

              Total Sales ($CDN):

            $500,000 to $999,999

				Product / Service / Licensing

                              Service Name:

                            Web Development

                            We provide web development and communication services to businesses, government and non-profit organizations.

                              Service Name:

                            Web Design

                            We design websites that create social change through building members, engaging constituents, and increasing donations.

                              Service Name:

                            Social Media Strategy

                            Managing your online presence is a bigger part of the web today than it ever has been. It's a huge tangled web of tweets, blogs, Facebook pages, campaign efforts, constituent relationship management systems (CRMs) and more.

We create websites that integrate seamlessly with all the parts of your online presence. This starts with building a strong site that forms the center of your Digital Ecology. We also recommend and coordinate all the other online pieces you need.

                              Service Name:

                            Campaign

                            We develop digital campaigns that assist in list building, driving engagement with members and constituents, and have impacts on the issues at hand.

  top of page

					Market profile

                        Alliances:

Sales/Marketing

Technology

                          Strategic alliances:

                        We believe that Canadian digital media content has a place on the international stage and look for partners in other areas to help develop this industry.

                          Industry sector market interests:

Consumer Products

Culture

Information Technology and Telecommunications

Tourism

              Geographic markets:

                  Export experience:

United States

California

Washington

                  Actively pursuing:

China

Indonesia

United Kingdom

Arizona

  top of page

					Sector information

                Key / Major clients:

              A strength of Agentic is the breadth of clients and business sectors that our team has had the opportunity to serve. Our work primarily encompasses projects on behalf of socially progressive not-for-profit societies, public sector agencies, and private sector organizations and programs whose agendas are focused on creating public and common good. We are pleased to introduce you to some of our recent clients.

Aboriginal Peoples Television Network

BC Electoral Boundaries Commission

Canada Mortgage and Housing Corp.

Canadian Interactive Alliance

Canadian Tourism Commission

CBC Radio

CBC Television

 Citizens' Services

City of Vancouver

College of New Caledonia

Community Legal Education Ontario

Council of Canadians

Ecotrust Canada

First Nations Education

First Nations Technology Council

Genocide Intervention Network

Histori.ca

Indian and Northern Affairs Canada

Industry Canada

Jazz Festivals Canada

Ministry of Labour and

MOSAIC

New Media BC

Simon Fraser University

                Success stories:

              1. The Agentic approach starts with gaining a fundamental understanding of our client's requirements. We do this through interviews and a deep understanding of the many business and operating models we have observed in action over 15 years in this fast-moving business.

2. Always mindful of our guiding principles, we strive to deliver innovative and cost-effective solutions in a timely manner for our clients. Keeping our word is important to us and we are fair and honest in all dealings with our clients.

3. We fundamentally believe in enabling our clients to have the worldwide web become an important channel in their relationships with constituents, team members, and stakeholders.

                Testimonial:

              ________________________________________

Agentic was a perfect partner for us on our website journey. We had two goals: to redesign our website and to create a more dynamic online presence. We came to Agentic with high expectations based on their previous work and their excellent process and they delivered. Agentic worked with us closely and attentively in a collaborative fashion: responding to our needs and wishes and gently guiding us toward new solutions when those were needed. They were professional, on time, and a pleasure to work with throughout. They were also reasonably priced. We want to especially commend the superb project management.

Limor Peer, Associate Director for Research

Yale University , Institution for Social and Policy Studies

________________________________________

Agentic took a very collaborative and intuitive approach to the redesign of our website and CRM. We required Agentic to take a complex mix of user requirements, expertise, and resources and to create an enhanced website and CMS on new technical platforms (Drupal and CiviCRM). Under their professional and collegial direction, we built an optimized site with enhanced visual appeal and usability and, more importantly, the potential for increased interaction with our growing adoption community of families, professionals, and advocates.

Mary Caros, Development & Communications Manager

Adoptive Families Association of BC

________________________________________

One of our foundation donors lapsed as a funder, but just came back on board. They contacted us out of the blue following the Annual Report mailing and said they love the new look and the new website. They felt more engaged and offered us additional unrestricted funding. Another funder told us that they'll re-engage with us now that we have beefed up our communications work. Our new Vice President is impressed. 'I've not heard of such a direct/tangible pay back for this type of investment before,' he wrote in an email to staff. Thanks again for the great work on the website."

Eric Enno Tam, former Communications Manager

Ecotrust Canada

					Third-Party Information Liability Disclaimer

					Some of the information on this Web page has been provided by external sources. The Government of Canada is not responsible for the accuracy, reliability or currency of the information supplied by external sources. Users wishing to rely upon this information should consult directly with the source of the information. Content provided by external sources is not subject to official languages, privacy and accessibility requirements.

				Contacts

				Contact information

                Phillip
                Djwa

                  Title:

                President

                    Area of Responsibility:

                    Management Executive.

                  Telephone:

                (604) 255-2131

                  Ext:

                101

                  Facsimile:

                (604) 255-2505

                    Email:

                  agentic-info@agentic.ca

				Description

				Company description

            Country of Ownership:

              Canada

              Year Established:

            2000

            Exporting:

              Yes

                Primary Industry (NAICS):

				541510 - Computer Systems Design and Related Services

            Alternate Industries (NAICS):

            519130 - Internet Publishing and Broadcasting, and Web Search Portals

            541910 - Marketing Research and Public Opinion Polling

            Primary Business Activity:

            Services

              Total Sales ($CDN):

            $500,000 to $999,999

				Products, services and licensing

				Product / Service / Licensing

                              Service Name:

                            Web Development

                            We provide web development and communication services to businesses, government and non-profit organizations.

                              Service Name:

                            Web Design

                            We design websites that create social change through building members, engaging constituents, and increasing donations.

                              Service Name:

                            Social Media Strategy

                            Managing your online presence is a bigger part of the web today than it ever has been. It's a huge tangled web of tweets, blogs, Facebook pages, campaign efforts, constituent relationship management systems (CRMs) and more.

We create websites that integrate seamlessly with all the parts of your online presence. This starts with building a strong site that forms the center of your Digital Ecology. We also recommend and coordinate all the other online pieces you need.

                              Service Name:

                            Campaign

                            We develop digital campaigns that assist in list building, driving engagement with members and constituents, and have impacts on the issues at hand.

					Market

					Market profile

                        Alliances:

Sales/Marketing

Technology

                          Strategic alliances:

                        We believe that Canadian digital media content has a place on the international stage and look for partners in other areas to help develop this industry.

                          Industry sector market interests:

Consumer Products

Culture

Information Technology and Telecommunications

Tourism

              Geographic markets:

                  Export experience:

United States

California

Washington

                  Actively pursuing:

China

Indonesia

United Kingdom

Arizona

					Sector

					Sector information

                Key / Major clients:

              A strength of Agentic is the breadth of clients and business sectors that our team has had the opportunity to serve. Our work primarily encompasses projects on behalf of socially progressive not-for-profit societies, public sector agencies, and private sector organizations and programs whose agendas are focused on creating public and common good. We are pleased to introduce you to some of our recent clients.

Aboriginal Peoples Television Network

BC Electoral Boundaries Commission

Canada Mortgage and Housing Corp.

Canadian Interactive Alliance

Canadian Tourism Commission

CBC Radio

CBC Television

 Citizens' Services

City of Vancouver

College of New Caledonia

Community Legal Education Ontario

Council of Canadians

Ecotrust Canada

First Nations Education

First Nations Technology Council

Genocide Intervention Network

Histori.ca

Indian and Northern Affairs Canada

Industry Canada

Jazz Festivals Canada

Ministry of Labour and

MOSAIC

New Media BC

Simon Fraser University

                Success stories:

              1. The Agentic approach starts with gaining a fundamental understanding of our client's requirements. We do this through interviews and a deep understanding of the many business and operating models we have observed in action over 15 years in this fast-moving business.

2. Always mindful of our guiding principles, we strive to deliver innovative and cost-effective solutions in a timely manner for our clients. Keeping our word is important to us and we are fair and honest in all dealings with our clients.

3. We fundamentally believe in enabling our clients to have the worldwide web become an important channel in their relationships with constituents, team members, and stakeholders.

                Testimonial:

              ________________________________________

Agentic was a perfect partner for us on our website journey. We had two goals: to redesign our website and to create a more dynamic online presence. We came to Agentic with high expectations based on their previous work and their excellent process and they delivered. Agentic worked with us closely and attentively in a collaborative fashion: responding to our needs and wishes and gently guiding us toward new solutions when those were needed. They were professional, on time, and a pleasure to work with throughout. They were also reasonably priced. We want to especially commend the superb project management.

Limor Peer, Associate Director for Research

Yale University , Institution for Social and Policy Studies

________________________________________

Agentic took a very collaborative and intuitive approach to the redesign of our website and CRM. We required Agentic to take a complex mix of user requirements, expertise, and resources and to create an enhanced website and CMS on new technical platforms (Drupal and CiviCRM). Under their professional and collegial direction, we built an optimized site with enhanced visual appeal and usability and, more importantly, the potential for increased interaction with our growing adoption community of families, professionals, and advocates.

Mary Caros, Development & Communications Manager

Adoptive Families Association of BC

________________________________________

One of our foundation donors lapsed as a funder, but just came back on board. They contacted us out of the blue following the Annual Report mailing and said they love the new look and the new website. They felt more engaged and offered us additional unrestricted funding. Another funder told us that they'll re-engage with us now that we have beefed up our communications work. Our new Vice President is impressed. 'I've not heard of such a direct/tangible pay back for this type of investment before,' he wrote in an email to staff. Thanks again for the great work on the website."

Eric Enno Tam, former Communications Manager

Ecotrust Canada

    Last Update Date 2016-02-11

Date Modified:

      <time>2017-03-02</time>

About government

Contact us

Departments and agencies

Public service and military

News

Treaties, laws and regulations

Government-wide reporting

Prime Minister

How government works

Open government

About this site

Social media

Mobile applications

About Canada.ca

Terms and conditions

Privacy

Top of Page

<object type="image/svg+xml" tabindex="-1" role="img" data="/utils/scripts/_WET_4-0/apps/themes-dist/gcweb/assets/wmms-blk.svg" aria-label="Symbol of the Government of Canada"></object>


text:
package io.subutai.core.metric.impl.dao;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.TypedQuery;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

import io.subutai.common.exception.DaoException;
import io.subutai.core.metric.impl.model.Subscriber;

public class SubscriberDao
{
    private EntityManagerFactory emf;
    private Logger LOGGER = LoggerFactory.getLogger( SubscriberDao.class );

    public SubscriberDao( final EntityManagerFactory emf ) throws DaoException
    {
        Preconditions.checkNotNull( emf, "EntityManagerFactory cannot be null." );
        this.emf = emf;
        try
        {
            this.emf.createEntityManager().close();
        }
        catch ( Exception e )
        {
            LOGGER.error( "Couldn't initialize EntityManager in SubscriberDataService." );
            throw new DaoException( e );
        }
    }

    public void setEntityManagerFactory( final EntityManagerFactory emf )
    {
        Preconditions.checkNotNull( emf, " EntityManagerFactory cannot be null." );
        this.emf = emf;
    }

    public void update( final String environmentId, final String subscriberId ) throws DaoException
    {
        EntityManager em = emf.createEntityManager();
        try
        {
            em.getTransaction().begin();

            Subscriber subscriber = new Subscriber( environmentId, subscriberId );
            em.merge( subscriber );

            em.getTransaction().commit();
        }
        catch ( Exception e )
        {
            LOGGER.error( "Instance is not an entity or command invoked on a container-managed entity manager." );
            if ( em.getTransaction().isActive() )
            {
                em.getTransaction().rollback();
            }
            throw new DaoException( e );
        }
        finally
        {
            em.close();
        }
    }

    public void remove( final String environmentId, final String subscriberId ) throws DaoException
    {
        EntityManager em = emf.createEntityManager();
        try
        {
            em.getTransaction().begin();

            Query query = em.createQuery(
                    "DELETE FROM Subscriber s WHERE s.environmentId = :environmentId AND s.subscriberId = "
                            + ":subscriberId" );
            query.setParameter( "environmentId", environmentId );
            query.setParameter( "subscriberId", subscriberId );
            query.executeUpdate();

            em.getTransaction().commit();
        }
        catch ( Exception e )
        {
            if ( em.getTransaction().isActive() )
            {
                em.getTransaction().rollback();
            }
            LOGGER.error( "Query string found to be invalid." );
            throw new DaoException( e );
        }
        finally
        {
            em.close();
        }
    }

    public Set<String> findHandlersByEnvironment( final String environmentId ) throws DaoException
    {
        Set<String> result = new HashSet<>();
        EntityManager em = emf.createEntityManager();
        try
        {
            em.getTransaction().begin();

            TypedQuery<String> query =
                    em.createQuery( "select s.subscriberId from Subscriber s where s.environmentId = :environmentId",
                            String.class );
            query.setParameter( "environmentId", environmentId );
            result.addAll( query.getResultList() );

            em.getTransaction().commit();
        }
        catch ( Exception e )
        {
            if ( em.getTransaction().isActive() )
            {
                em.getTransaction().rollback();
            }
            LOGGER.error( "Error getting subscriberIds" );
            throw new DaoException( e );
        }
        finally
        {
            em.close();
        }
        return result;
    }
}


text:
{strip}

{assign var="tmpdesc" value="{$datasql_table}.{$datasql_edit_fields[ti].row[i].col[j].field}"}
{assign var="tmpfileinfo" value="{$datasql_edit_fields[ti].row[i].col[j].field}_fileinfo"}

	{if isset($apfra_db_desc[$tmpdesc])}{$apfra_db_desc[$tmpdesc]}{else}{$tmpdesc}{/if}{if isset($datasql_edit_fields[ti].row[i].col[j].required) && $datasql_edit_fields[ti].row[i].col[j].required == 1} *{/if}

	{if $data.$tmpfileinfo}

{$data.$tmpfileinfo["name"]} ({$data.$tmpfileinfo["size"]} bytes)

	{/if}

			<input type="text" class="form-control" readonly placeholder="Wählen Sie eine Datei aus">

					<input type="file" id="fd_{$datasql_edit_fields[ti].row[i].col[j].field}" name="fd_{$datasql_edit_fields[ti].row[i].col[j].field}" data-error="Bitte füllen Sie dieses Feld aus."
						{if isset($datasql_edit_fields[ti].row[i].col[j].required) && $datasql_edit_fields[ti].row[i].col[j].required == 1} required="required"{/if}
						{if $apfra_rights[$module]["upd"] == 0} readonly="readonly"{/if}/> {* TODO: multiple ?*}

		{if $data.$tmpfileinfo}

		{/if}

(max. {$uploadsize} Bytes)

{/strip}

{strip}
{/strip}


text:
import { finalize } from '../operators/finalize';
/**
 * Returns an Observable that mirrors the source Observable, but will call a specified function when
 * the source terminates on complete or error.
 * @param {function} callback Function to be called when source terminates.
 * @return {Observable} An Observable that mirrors the source, but will call the specified function on termination.
 * @method finally
 * @owner Observable
 */
export function _finally(callback) {
    return finalize(callback)(this);
}
//# sourceMappingURL=finally.js.map


text:
// Tokenizer.h

#pragma once

//=========================================================================================
// TODO: It would be nice if the tokenizer could recognize and skip over comments.
class CalcLib::Token : public Utilities::List::Item
{
public:

	enum Type
	{
		TYPE_UNKNOWN,
		TYPE_NUMBER,
		TYPE_ABSTRACT_NUMBER,
		TYPE_OPERATOR,
		TYPE_NAME,
		TYPE_LEFT_PARAN,
		TYPE_RIGHT_PARAN,
		TYPE_DELIMETER,
		TYPE_STRING,
	};

	Token( void );
	virtual ~Token( void );

	char* string;
	Type type;
	int lineNumber;
};

//=========================================================================================
class CalcLib::Tokenizer
{
public:

	Tokenizer( void );
	virtual ~Tokenizer( void );

	bool Tokenize( const char* mathExpression, Utilities::List& listOfTokens, Environment& environment );

private:

	// TODO: Change this to a set of OR-able flags and fix the bugs in the tokenizer.
	enum TokenConsumption
	{
		CONSUME_NON_WHITE_SPACE,
		CONSUME_NUMERICAL_ONLY,
		CONSUME_ALPHABETICAL_AND_NUMERICAL_ONLY,
		CONSUME_SINGLE_CHARACTER,
		CONSUME_TWO_CHARACETERS,
		CONSUME_STRING,
	};

	bool IsWhiteSpace( const char* parsePosition );
	const char* EatWhiteSpace( const char*& parsePosition, int& lineNumber );
	Token* ConsumeToken( const char*& parsePosition );
	bool IsOperatorToken( const char* parsePosition );
	char* CreateTokenString( const char*& parsePosition, TokenConsumption tokenConsumption );
	bool CanConsumeCharacter( char character, int consumptionCount, char initialCharacter, TokenConsumption tokenConsumption );
};

// Tokenizer.h


text:
package com.asakusafw.utils.java.model.syntax;

/**
 * An interface which represents while statement.
 *

 *
 Specified In:

 *
 {@code [JLS3:14.12] The while Statement}

 *

 *

 */
public interface WhileStatement
        extends Statement {

    /**
     * Returns the condition expression.
     * @return the condition expression
     */
    Expression getCondition();

    /**
     * Returns the loop body.
     * @return the loop body
     */
    Statement getBody();
}


text:
package ch.bretscherhochstrasser.android.stickyviewpager.sample;

public class ClassicViewPagerActivity extends AbstractViewPagerActivty {

	@Override
	void onSetContentView() {
		setContentView(R.layout.classic_view_pager_activity);
	}

	@Override
	void onSetTitle() {
		setTitle(R.string.classicViewPagerActivityTitle);
	}

}


text:
using System;

namespace Mjcheetham.VisualStudio.ProjectSystemMonitor
{
    internal class ProjectClosingEventArgs : EventArgs
    {
        public bool Removed { get; }

        public ProjectClosingEventArgs(bool removed)
        {
            Removed = removed;
        }
    }
}


text:
.class public Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;
.super Lcom/pittvandewitt/viperfx/base/b;

# interfaces
.implements Landroid/view/View$OnClickListener;
.implements Landroid/widget/SeekBar$OnSeekBarChangeListener;

# instance fields
.field mLimiterEnable:Landroid/widget/CheckBox;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mOutputGainEnable:Landroid/widget/CheckBox;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mOutputPanEnable:Landroid/widget/CheckBox;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mOutputVals:[Ljava/lang/String;
    .annotation build Lbutterknife/BindArray;
    .end annotation
.end field

.field mOutputVolVals:[Ljava/lang/String;
    .annotation build Lbutterknife/BindArray;
    .end annotation
.end field

.field mOutputVols:[Ljava/lang/String;
    .annotation build Lbutterknife/BindArray;
    .end annotation
.end field

.field mOutputs:[Ljava/lang/String;
    .annotation build Lbutterknife/BindArray;
    .end annotation
.end field

.field mSbLimiter:Landroid/widget/SeekBar;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mSbOutputGain:Landroid/widget/SeekBar;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mSbOutputPan:Landroid/widget/SeekBar;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mTvLimiterVal:Landroid/widget/TextView;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mTvOutputGainVal:Landroid/widget/TextView;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

.field mTvOutputPanVal:Landroid/widget/TextView;
    .annotation build Lbutterknife/BindView;
    .end annotation
.end field

# direct methods
.method public constructor <init>()V
    .locals 0

    invoke-direct {p0}, Lcom/pittvandewitt/viperfx/base/b;-><init>()V

    return-void
.end method

.method private a()V
    .locals 1

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputPanEnable:Landroid/widget/CheckBox;

    invoke-virtual {v0, p0}, Landroid/widget/CheckBox;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputGainEnable:Landroid/widget/CheckBox;

    invoke-virtual {v0, p0}, Landroid/widget/CheckBox;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mLimiterEnable:Landroid/widget/CheckBox;

    invoke-virtual {v0, p0}, Landroid/widget/CheckBox;->setOnClickListener(Landroid/view/View$OnClickListener;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbOutputPan:Landroid/widget/SeekBar;

    invoke-virtual {v0, p0}, Landroid/widget/SeekBar;->setOnSeekBarChangeListener(Landroid/widget/SeekBar$OnSeekBarChangeListener;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbOutputGain:Landroid/widget/SeekBar;

    invoke-virtual {v0, p0}, Landroid/widget/SeekBar;->setOnSeekBarChangeListener(Landroid/widget/SeekBar$OnSeekBarChangeListener;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbLimiter:Landroid/widget/SeekBar;

    invoke-virtual {v0, p0}, Landroid/widget/SeekBar;->setOnSeekBarChangeListener(Landroid/widget/SeekBar$OnSeekBarChangeListener;)V

    return-void
.end method

.method private b()V
    .locals 4

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbOutputPan:Landroid/widget/SeekBar;

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    const-string v2, "viper4android.headphonefx.channelpan"

    const-string v3, "0"

    invoke-interface {v1, v2, v3}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-static {v1}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;

    move-result-object v1

    invoke-virtual {v1}, Ljava/lang/Integer;->intValue()I

    move-result v1

    add-int/lit8 v1, v1, 0x64

    invoke-virtual {v0, v1}, Landroid/widget/SeekBar;->setProgress(I)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mTvOutputPanVal:Landroid/widget/TextView;

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    const-string v2, "viper4android.headphonefx.channelpan"

    const-string v3, "0"

    invoke-interface {v1, v2, v3}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputVolVals:[Ljava/lang/String;

    invoke-static {v0}, Ljava/util/Arrays;->asList([Ljava/lang/Object;)Ljava/util/List;

    move-result-object v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    const-string v2, "viper4android.headphonefx.outvol"

    const-string v3, "100"

    invoke-interface {v1, v2, v3}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-interface {v0, v1}, Ljava/util/List;->indexOf(Ljava/lang/Object;)I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbOutputGain:Landroid/widget/SeekBar;

    neg-int v2, v0

    add-int/lit8 v2, v2, 0x15

    mul-int/lit8 v2, v2, 0xa

    invoke-virtual {v1, v2}, Landroid/widget/SeekBar;->setProgress(I)V

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mTvOutputGainVal:Landroid/widget/TextView;

    iget-object v2, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputVols:[Ljava/lang/String;

    aget-object v0, v2, v0

    invoke-virtual {v1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputVals:[Ljava/lang/String;

    invoke-static {v0}, Ljava/util/Arrays;->asList([Ljava/lang/Object;)Ljava/util/List;

    move-result-object v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    const-string v2, "viper4android.headphonefx.limiter"

    const-string v3, "100"

    invoke-interface {v1, v2, v3}, Landroid/content/SharedPreferences;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

    move-result-object v1

    invoke-interface {v0, v1}, Ljava/util/List;->indexOf(Ljava/lang/Object;)I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbLimiter:Landroid/widget/SeekBar;

    neg-int v2, v0

    add-int/lit8 v2, v2, 0x5

    mul-int/lit8 v2, v2, 0xa

    invoke-virtual {v1, v2}, Landroid/widget/SeekBar;->setProgress(I)V

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mTvLimiterVal:Landroid/widget/TextView;

    iget-object v2, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputs:[Ljava/lang/String;

    aget-object v0, v2, v0

    invoke-virtual {v1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    return-void
.end method

# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 3

    const/4 v2, 0x1

    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputPanEnable:Landroid/widget/CheckBox;

    invoke-virtual {v1}, Landroid/widget/CheckBox;->getId()I

    move-result v1

    if-ne v0, v1, :cond_1

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputPanEnable:Landroid/widget/CheckBox;

    invoke-virtual {v0, v2}, Landroid/widget/CheckBox;->setChecked(Z)V

    :cond_0
    :goto_0
    invoke-virtual {p0}, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->getActivity()Landroid/app/Activity;

    move-result-object v0

    new-instance v1, Landroid/content/Intent;

    const-string v2, "com.pittvandewitt.viperfx.UPDATE"

    invoke-direct {v1, v2}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V

    invoke-virtual {v0, v1}, Landroid/app/Activity;->sendBroadcast(Landroid/content/Intent;)V

    return-void

    :cond_1
    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputGainEnable:Landroid/widget/CheckBox;

    invoke-virtual {v1}, Landroid/widget/CheckBox;->getId()I

    move-result v1

    if-ne v0, v1, :cond_2

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputGainEnable:Landroid/widget/CheckBox;

    invoke-virtual {v0, v2}, Landroid/widget/CheckBox;->setChecked(Z)V

    goto :goto_0

    :cond_2
    invoke-virtual {p1}, Landroid/view/View;->getId()I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mLimiterEnable:Landroid/widget/CheckBox;

    invoke-virtual {v1}, Landroid/widget/CheckBox;->getId()I

    move-result v1

    if-ne v0, v1, :cond_0

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mLimiterEnable:Landroid/widget/CheckBox;

    invoke-virtual {v0, v2}, Landroid/widget/CheckBox;->setChecked(Z)V

    goto :goto_0
.end method

.method public onCreateView(Landroid/view/LayoutInflater;Landroid/view/ViewGroup;Landroid/os/Bundle;)Landroid/view/View;
    .locals 2

    const v0, 0x7f040035

    const/4 v1, 0x0

    invoke-virtual {p1, v0, p2, v1}, Landroid/view/LayoutInflater;->inflate(ILandroid/view/ViewGroup;Z)Landroid/view/View;

    move-result-object v0

    invoke-static {p0, v0}, Lbutterknife/ButterKnife;->a(Ljava/lang/Object;Landroid/view/View;)Lbutterknife/Unbinder;

    invoke-direct {p0}, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a()V

    invoke-direct {p0}, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->b()V

    return-object v0
.end method

.method public onProgressChanged(Landroid/widget/SeekBar;IZ)V
    .locals 4

    invoke-virtual {p1}, Landroid/widget/SeekBar;->getId()I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbOutputPan:Landroid/widget/SeekBar;

    invoke-virtual {v1}, Landroid/widget/SeekBar;->getId()I

    move-result v1

    if-ne v0, v1, :cond_1

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mTvOutputPanVal:Landroid/widget/TextView;

    new-instance v1, Ljava/lang/StringBuilder;

    invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V

    add-int/lit8 v2, p2, -0x64

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;

    move-result-object v1

    const-string v2, ""

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v1

    invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v1

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    iget-object v0, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    invoke-interface {v0}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;

    move-result-object v0

    const-string v1, "viper4android.headphonefx.channelpan"

    new-instance v2, Ljava/lang/StringBuilder;

    invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V

    add-int/lit8 v3, p2, -0x64

    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;

    move-result-object v2

    const-string v3, ""

    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v2

    invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v2

    invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;

    move-result-object v0

    invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->apply()V

    :cond_0
    :goto_0
    invoke-virtual {p0}, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->getActivity()Landroid/app/Activity;

    move-result-object v0

    new-instance v1, Landroid/content/Intent;

    const-string v2, "com.pittvandewitt.viperfx.UPDATE"

    invoke-direct {v1, v2}, Landroid/content/Intent;-><init>(Ljava/lang/String;)V

    invoke-virtual {v0, v1}, Landroid/app/Activity;->sendBroadcast(Landroid/content/Intent;)V

    return-void

    :cond_1
    invoke-virtual {p1}, Landroid/widget/SeekBar;->getId()I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbOutputGain:Landroid/widget/SeekBar;

    invoke-virtual {v1}, Landroid/widget/SeekBar;->getId()I

    move-result v1

    if-ne v0, v1, :cond_2

    div-int/lit8 v0, p2, 0xa

    add-int/lit8 v0, v0, -0x15

    neg-int v0, v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mTvOutputGainVal:Landroid/widget/TextView;

    iget-object v2, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputVols:[Ljava/lang/String;

    aget-object v2, v2, v0

    invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    invoke-interface {v1}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;

    move-result-object v1

    const-string v2, "viper4android.headphonefx.outvol"

    iget-object v3, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputVolVals:[Ljava/lang/String;

    aget-object v0, v3, v0

    invoke-interface {v1, v2, v0}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;

    move-result-object v0

    invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->apply()V

    goto :goto_0

    :cond_2
    invoke-virtual {p1}, Landroid/widget/SeekBar;->getId()I

    move-result v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mSbLimiter:Landroid/widget/SeekBar;

    invoke-virtual {v1}, Landroid/widget/SeekBar;->getId()I

    move-result v1

    if-ne v0, v1, :cond_0

    div-int/lit8 v0, p2, 0xa

    add-int/lit8 v0, v0, -0x5

    neg-int v0, v0

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mTvLimiterVal:Landroid/widget/TextView;

    iget-object v2, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputs:[Ljava/lang/String;

    aget-object v2, v2, v0

    invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    iget-object v1, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->a:Landroid/content/SharedPreferences;

    invoke-interface {v1}, Landroid/content/SharedPreferences;->edit()Landroid/content/SharedPreferences$Editor;

    move-result-object v1

    const-string v2, "viper4android.headphonefx.limiter"

    iget-object v3, p0, Lcom/pittvandewitt/viperfx/screen/FxLimiterFragment;->mOutputVals:[Ljava/lang/String;

    aget-object v0, v3, v0

    invoke-interface {v1, v2, v0}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;

    move-result-object v0

    invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->apply()V

    goto :goto_0
.end method

.method public onStartTrackingTouch(Landroid/widget/SeekBar;)V
    .locals 0

    return-void
.end method

.method public onStopTrackingTouch(Landroid/widget/SeekBar;)V
    .locals 0

    return-void
.end method


text:
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/hud_display/graph.h"

#include <algorithm>
#include <limits>
#include <sstream>

#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkPoint.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect_f.h"

namespace ash {
namespace hud_display {

Graph::Graph(size_t max_data_points,
             Baseline baseline,
             Fill fill,
             Style style,
             SkColor color)
    : baseline_(baseline), fill_(fill), style_(style), color_(color) {
  DCHECK_LT(max_data_points, data_.BufferSize());
  max_data_points_ = std::min(max_data_points, data_.BufferSize() - 1);
}

Graph::~Graph() {}

void Graph::AddValue(float value, float unscaled_value) {
  data_.SaveToBuffer(value);
  unscaled_data_.SaveToBuffer(unscaled_value);
}

void Graph::Layout(const gfx::Rect& graph_bounds, const Graph* base) {
  graph_bounds_ = graph_bounds;

  const float scale_x = graph_bounds.width() / (float)max_data_points_;

  // Assume data is already scaled to [0-1], which will map to full
  // |graph_bounds| height.
  const float scale_y = graph_bounds.height();

  // Let every graph to occupy at least given amount of pixels.
  const int pixel_adjust = (baseline_ == Baseline::BASELINE_BOTTOM) ? -1 : 1;

  // Bottom path is always base. So it's visually below the current line when
  // BASELINE_BOTTOM and above current graph when BASELINE_TOP.
  // top_path_ is similarly inverted.
  bottom_path_.resize(0);
  if (base) {
    bottom_path_.reserve(base->top_path().size());
    bottom_path_style_ = base->style_;
    for (const SkPoint& point : base->top_path())
      bottom_path_.push_back({point.x(), point.y() + pixel_adjust});
  }
  top_path_.resize(0);
  top_path_.reserve(max_data_points_);
  size_t i = 0;
  // base::RingBuffer<> does not conform to C++ containers specification, so
  // it's End() is actually Back().
  for (Graph::Data::Iterator it = data_.End(); it; --it) {
    const float value = **it;

    float x = graph_bounds.x() + (max_data_points_ - i) * scale_x;
    float y =
        (baseline_ == Baseline::BASELINE_BOTTOM ? -1 : 1) * value * scale_y;
    if (bottom_path_.size()) {
      CHECK_LT(i, bottom_path_.size());
      // Adjust to the single pixel line added above.
      y = bottom_path_[i].y() - pixel_adjust + y;
    } else {
      y = (baseline_ == Baseline::BASELINE_BOTTOM ? graph_bounds.bottom()
                                                  : graph_bounds.y()) +
          y;
    }
    top_path_.push_back({x, y});
    ++i;
    if (i >= max_data_points_)
      break;
  }

  // This is the first layer from the start and it is filled and is non-empty.
  if (!base && fill_ != Graph::Fill::NONE && !top_path_.empty()) {
    gfx::RectF graph_bounds_f(graph_bounds);
    if (baseline_ == Baseline::BASELINE_BOTTOM) {
      bottom_path_.push_back({graph_bounds_f.right(), graph_bounds_f.bottom()});
      bottom_path_.push_back({top_path_.back().x(), graph_bounds_f.bottom()});
    } else {
      bottom_path_.push_back({graph_bounds_f.right(), graph_bounds_f.y()});
      bottom_path_.push_back({top_path_.back().x(), graph_bounds_f.y()});
    }
  }
}

void Graph::Draw(gfx::Canvas* canvas) const {
  if (top_path_.empty())
    return;

  SkPath path;
  path.moveTo(top_path_.front());

  const auto draw_top_line = [](const std::vector<SkPoint>& top_path,
                                const auto& draw_point, SkPath& out_path) {
    SkPoint previous_point = top_path.front();
    for (std::vector<SkPoint>::const_iterator it = top_path.begin();
         it != top_path.end(); ++it) {
      // For the top line we are already here.
      if (it == top_path.begin())
        continue;
      // Depending on the line type, |draw_point| may use the previous point.
      draw_point(*it, previous_point, out_path);
    }
  };
  const auto draw_bottom_line = [](const std::vector<SkPoint>& bottom_path,
                                   const auto& draw_point, SkPath& result) {
    SkPoint previous_point = bottom_path.back();
    for (std::vector<SkPoint>::const_reverse_iterator it =
             bottom_path.crbegin();
         it != bottom_path.crend(); ++it) {
      // Bottom line needs line to the first point too.
      // Depending on the line type, |draw_point| may use the previous point.
      draw_point(*it, previous_point, result);
    }
  };

  // This is used to draw both top and bottom Style::LINES paths.
  const auto draw_lines_point =
      [](const SkPoint& point, const SkPoint& /*previous_point*/,
         SkPath& out_path) { out_path.lineTo(point); };
  // Top and bottom Style::SKYLINE drawing functions are symmetric.
  const auto draw_skyline_point =
      [](const SkPoint& point, SkPoint& previous_point, SkPath& out_path) {
        out_path.lineTo(SkPoint::Make(point.x(), previous_point.y()));
        out_path.lineTo(point);
        previous_point = point;
      };
  const auto draw_bottom_skyline_point =
      [](const SkPoint& point, SkPoint& previous_point, SkPath& out_path) {
        out_path.lineTo(SkPoint::Make(previous_point.x(), point.y()));
        out_path.lineTo(point);
        previous_point = point;
      };
  switch (style_) {
    case Style::LINES:
      draw_top_line(top_path_, draw_lines_point, path);
      break;
    case Style::SKYLINE:
      draw_top_line(top_path_, draw_skyline_point, path);
      break;
  }
  if (fill_ == Graph::Fill::SOLID) {
    switch (bottom_path_style_) {
      case Style::LINES:
        draw_bottom_line(bottom_path_, draw_lines_point, path);
        break;
      case Style::SKYLINE:
        draw_bottom_line(bottom_path_, draw_bottom_skyline_point, path);
        break;
    }
  }
  cc::PaintFlags flags;
  flags.setAntiAlias(true);
  flags.setBlendMode(SkBlendMode::kSrc);
  const cc::PaintFlags::Style style = (fill_ == Graph::Fill::NONE)
                                          ? cc::PaintFlags::kStroke_Style
                                          : cc::PaintFlags::kFill_Style;
  flags.setStyle(style);
  flags.setStrokeWidth(1);
  flags.setColor(color_);
  canvas->DrawPath(path, flags);
}

void Graph::UpdateLastValue(float value, float unscaled_value) {
  const size_t last_index = data_.BufferSize() - 1;
  if (!data_.IsFilledIndex(last_index))
    return;

  *data_.MutableReadBuffer(last_index) = value;
  *unscaled_data_.MutableReadBuffer(last_index) = unscaled_value;
}

float Graph::GetUnscaledValueAt(size_t index) const {
  if (index >= max_data_points_)
    return 0;

  // 0 - the oldest value
  // BufferSize() - 1  - the newest value.
  const size_t raw_index = index < unscaled_data_.BufferSize()
                               ? unscaled_data_.BufferSize() - 1 - index
                               : 0;

  // It will CHECK() if index is not populated.
  if (!unscaled_data_.IsFilledIndex(raw_index))
    return 0;

  return unscaled_data_.ReadBuffer(raw_index);
}

bool Graph::IsFilledIndex(size_t index) const {
  if (index >= max_data_points_)
    return false;

  // 0 - the oldest value
  // BufferSize() - 1  - the newest value.
  const size_t raw_index =
      index < data_.BufferSize() ? data_.BufferSize() - 1 - index : 0;
  return data_.IsFilledIndex(raw_index);
}

void Graph::Reset() {
  data_.Clear();
  unscaled_data_.Clear();
}

#if !defined(NDEBUG)
std::string Graph::DebugDump(const std::string& name) const {
  std::ostringstream os;
  os << name << ": location BLxy  [" << graph_bounds_.x() << ", "
     << graph_bounds_.bottom() << "] TRxy [" << graph_bounds_.right() << ", "
     << graph_bounds_.y() << "]";
  const int topsize = static_cast<int>(top_path_.size());
  for (int i = 0; i < topsize; ++i) {
    if ((i > 5) && (i < topsize - 5)) {
      // Skip the middle part.
      os << "\t" << name << ": ...";
      i = topsize - 5;
    }
    if (fill_ == Graph::Fill::SOLID) {
      // Print filled graph as a set of vertical lines.
      if (top_path_.size() == bottom_path_.size()) {
        // Each point on the top has matching point on the bottom.
        os << "\t" << name << ": " << i << ": [" << bottom_path_[i].x() << ", "
           << bottom_path_[i].y() << "] -> [" << top_path_[i].x() << ", "
           << top_path_[i].y() << "]";
      } else {
        // This is the first graph in stack. Use bottom_path_[0].y() as
        // reference.
        os << "\t" << name << ": " << i << ": ["
           << ((i == 0) ? bottom_path_[0].x() : top_path_[i].x()) << ", "
           << bottom_path_[0].y() << "] -> [" << top_path_[i].x() << ", "
           << top_path_[i].y() << "]";
      }
    } else {
      // Print lines graph as a list of dots.
      os << "\t" << name << ": " << i << ": -> [" << top_path_[i].x() << ", "
         << top_path_[i].y() << "]";
    }
    os << "\n";
  }
  return os.str();
}
#endif

}  // namespace hud_display
}  // namespace ash


text:
@(admin: model.User, teachers: Seq[model.User], courses: Seq[model.Course])

<!DOCTYPE html>

        <title>Fénix - SIRS</title>
        <link href="@routes.Assets.at("bootstrap/css/bootstrap.min.css")" rel="stylesheet">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">

Admin (@admin.name)

Assign Teacher to Course

            <form class="form-horizontal" role="form" action="@controllers.admin.routes.AdminController.assignTeacherToCourseSubmit" method="post">

                    <select class="form-control" name="courseId">
                    @for(course <- courses) {
                        <option value="@course.id">@course.name</option>
                    }
                    </select>

                    <select class="form-control" name="teacherId">
                    @for(teacher <- teachers) {
                        <option value="@teacher.id">@teacher.name</option>
                    }
                    </select>

                        <button type="submit" class="btn btn-primary">Assign</button>

            </form>


text:
<?php

namespace Savander\TwServers\MasterServer;

/**
 * Class ServerResolver
 *
 * @package Savander\TwServers\Server
 */
class MasterServerResolver implements MasterServerResolverInterface
{

    # Time before timeout will appear in connection
    const CONNECTION_TIMEOUT = 2;

    /**
     * PACKET_LIST2 for 0.6+
     * https://github.com/teeworlds/teeworlds/blob/master/scripts/tw_api.py#L18-L22
     **/
    const DATA_TO_SEND = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreq2";

    /**
     * Array of servers ip addresses
     *
     * @var array
     */
    protected $serversList = [];

    protected $ipAddress;

    protected $port;

    protected $collectedData = false;

    /**
     * MasterServerResolverInterface constructor.
     *
     * @param string $ipAddress
     * @param        $port
     */
    public function __construct(
        string $ipAddress ,
        $port = self::DEFAULT_PORT_SERVER
    ) {
        $this->resolveMasterServer($ipAddress , $port);
        $this->ipAddress = $ipAddress;
        $this->port      = $port;
    }

    /**
     * Resolve server by IpAddress
     *
     * @param string $ipAddress
     * @param        $port
     *
     * @return bool
     */
    public function resolveMasterServer(
        string $ipAddress ,
        $port = self::DEFAULT_PORT_SERVER
    ): bool {
        if ($serverList = $this->getMasterServerData($ipAddress , $port)) {

            foreach ($serverList as $item) {
                $this->parseData($item);
            }
            $this->collectedData = true;

            return true;
        }

        return false;
    }

    /**
     * @param string $ipAddress
     * @param int    $port
     *
     * @return bool|array
     */
    protected function getMasterServerData(
        string $ipAddress ,
        int $port
    ) {
        $socket = fsockopen(
            "udp://$ipAddress" ,
            (int)$port ,
            $errno ,
            $errst ,
            self::CONNECTION_TIMEOUT
        );

        # If no data, timeout after specific time
        stream_set_timeout($socket , 1);

        if ($socket) {
            fwrite($socket , self::DATA_TO_SEND);
            $response = fread($socket , 2048);

            $data = [];

            while (strlen($response) >= 1) {
                $data[]   = $response;
                $response = fread($socket , 2048);
            }

            fclose($socket);

            return $data;
        }

        return false;
    }

    /**
     * @param string $data
     *
     * @return bool
     */
    public function parseData(string $data)
    {
        # Remove header
        $data       = substr($data , 14);
        $numServers = strlen($data) / 18;

        for ($iterator = 0; $iterator <= $numServers; $iterator++) {

            #IPv4
            if (substr($data , $iterator * 18 , 12)
                == "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"
            ) {
                $ipAddress = implode('.' , array_map("ord" ,
                    str_split(substr($data , $iterator * 18 + 12 , 4))));
            } #IPv6
            else {
                $ipAddress = implode(':' , array_map("ord" ,
                    str_split(substr($data , $iterator * 18 , 16))));
            }
            $port = (ord(substr($data , $iterator * 18 + 16)) << 8)
                + ord(substr($data , $iterator * 18 + 17));

            $this->serversList[] = [
                $ipAddress ,
                "ipAddress" => $ipAddress ,
                $port ,
                "port"      => $port ,
            ];
        }
    }

    /**
     * Return given server address
     *
     * @return string
     */
    public function getIpAddress(): string
    {
        return $this->ipAddress;
    }

    /**
     * Return given port
     *
     * @return int
     */
    public function getPort(): int
    {
        return (int)$this->port;
    }

    /**
     * Check if server gave data
     *
     * @return bool
     */
    public function collectedData(): bool
    {
        return $this->collectedData;
    }

    /**
     * return server list from master server
     *
     * @return array
     */
    public function getServers(): array
    {
        return $this->serversList;
    }
}