/**
* These are the list of room initialization ready states that Skylink would trigger.
* - The states indicates if the required connection information has been retrieved successfully from
* the platform server to start a connection.
* - These states are triggered when {{#crossLink "Skylink/init:method"}}init(){{/crossLink}} or
* {{#crossLink "Skylink/joinRoom:attr"}}joinRoom(){{/crossLink}} is invoked.
* @attribute READY_STATE_CHANGE
* @type JSON
* @param {Number} INIT Value 0
* The state when Skylink is at the initial state before retrieval.

* If all dependencies has been loaded, this would proceed to LOADING state.
* @param {Number} LOADING Value 1
* The state when Skylink starts retrieving the connection information from the platform server.

* This state occurs after INIT state and if retrieval is successful, this would
* proceed to COMPLETED state.
* @param {Number} COMPLETED Value 2
* The state when the connection information has been retrieved successfully.

* This state occurs after LOADING, and if it's
* {{#crossLink "Skylink/joinRoom:attr"}}joinRoom(){{/crossLink}} that is invoked, room connection
* would commerce.
* @param {Number} ERROR Value -1
* The state when an exception occured while retrieving the connection information.

* This state might be triggered when dependencies failed to load or HTTP retrieval fails.

* Reference {{#crossLink "Skylink/READY_STATE_CHANGE_ERROR:attr"}}READY_STATE_CHANGE_ERROR{{/crossLink}}
* to see the list of errors that might have triggered the ERROR state.
* @readOnly
* @component Room
* @for Skylink
* @since 0.1.0
*/
Skylink.prototype.READY_STATE_CHANGE = {
INIT: 0,
LOADING: 1,
COMPLETED: 2,
ERROR: -1
};
/**
* These are the list of room initialization ready state errors that Skylink has.
* - Ready state errors like ROOM_LOCKED, API_NOT_ENOUGH_CREDIT,
* API_NOT_ENOUGH_PREPAID_CREDIT, API_FAILED_FINDING_PREPAID_CREDIT and
* SCRIPT_ERROR has been removed as they are no longer supported.
* @attribute READY_STATE_CHANGE_ERROR
* @type JSON
* @param {Number} API_INVALID Value 4001
* The error when provided Application Key does not exists (invalid).

* For this error, it's recommended that you check if the Application Key exists in your account
* in the developer console.
* @param {Number} API_DOMAIN_NOT_MATCH Value 4002
* The error when application accessing from backend IP address is not valid for provided Application Key.

* This rarely (and should not) occur and it's recommended to report this issue if this occurs.
* @param {Number} API_CORS_DOMAIN_NOT_MATCH Value 4003
* The error when application accessing from the CORS domain is not valid for provided Application Key.

* For this error, it's recommended that you check the CORS configuration for the provided Application Key
* in the developer console.
* @param {Number} API_CREDENTIALS_INVALID Value 4004
* The error when credentials provided is not valid for provided Application Key.

* For this error, it's recommended to check the credentials provided in
* {{#crossLink "Skylink/init:method"}}init() configuration{{/crossLink}}.
* @param {Number} API_CREDENTIALS_NOT_MATCH Value 4005
* The error when credentials does not match as expected generated credentials for provided Application Key.

* For this error, it's recommended to check the credentials provided in
* {{#crossLink "Skylink/init:method"}}init() configuration{{/crossLink}}.
* @param {Number} API_INVALID_PARENT_KEY Value 4006
* The error when provided alias Application Key has an error because parent Application Key does not exists.

* For this error, it's recommended to provide another alias Application Key.
* @param {Number} API_NO_MEETING_RECORD_FOUND Value 4010
* The error when there is no meeting currently that is open or available to join
* for self at the current time in the selected room.

* For this error, it's recommended to retrieve the list of meetings and check if it exists using
* the [Meeting Resource REST API](https://temasys.atlassian.net/wiki/display/TPD/SkylinkAPI+-+Meeting+%28Persistent+Room%29+Resources).
* @param {Number} NO_SOCKET_IO Value 1
* The error when socket.io dependency is not loaded.

* For this error, it's recommended to load the
* [correct socket.io-client dependency](http://socket.io/download/) from the CDN.
* @param {Number} NO_XMLHTTPREQUEST_SUPPORT Value 2
* The error when XMLHttpRequest is not supported in current browser.

* For this error, it's recommended to ask user to switch to another browser that supports XMLHttpRequest.
* @param {Number} NO_WEBRTC_SUPPORT Value 3
* The error when WebRTC is not supported in current browser.

* For this error, it's recommended to ask user to switch to another browser that supports WebRTC.
* @param {Number} NO_PATH Value 4
* The error when constructed path is invalid.

* This rarely (and should not) occur and it's recommended to report this issue if this occurs.
* @param {Number} INVALID_XMLHTTPREQUEST_STATUS Value 5
* The error when XMLHttpRequest does not return a HTTP status code of 200 but a HTTP failure.

* This rarely (and should not) occur and it's recommended to report this issue if this occurs.
* @param {Number} ADAPTER_NO_LOADED Value 7
* The error when AdapterJS dependency is not loaded.

* For this error, it's recommended to load the
* [correct AdapterJS dependency](https://github.com/Temasys/AdapterJS/releases) from the CDN.
* @param {Number} XML_HTTP_REQUEST_ERROR Value -1
* The error when XMLHttpRequest failure on the network level when attempting to
* connect to the platform server to retrieve selected room connection information.

* This might happen when connection timeouts. If this is a persistent issue, it's recommended to report this issue.
* @readOnly
* @component Room
* @for Skylink
* @since 0.4.0
*/
Skylink.prototype.READY_STATE_CHANGE_ERROR = {
API_INVALID: 4001,
API_DOMAIN_NOT_MATCH: 4002,
API_CORS_DOMAIN_NOT_MATCH: 4003,
API_CREDENTIALS_INVALID: 4004,
API_CREDENTIALS_NOT_MATCH: 4005,
API_INVALID_PARENT_KEY: 4006,
API_NO_MEETING_RECORD_FOUND: 4010,
ROOM_LOCKED: 5001,
XML_HTTP_REQUEST_ERROR: -1,
NO_SOCKET_IO: 1,
NO_XMLHTTPREQUEST_SUPPORT: 2,
NO_WEBRTC_SUPPORT: 3,
NO_PATH: 4,
INVALID_XMLHTTPREQUEST_STATUS: 5,
SCRIPT_ERROR: 6,
ADAPTER_NO_LOADED: 7
};
/**
* These are the list of available platform signaling servers Skylink
* should connect to for faster connectivity.
* @attribute REGIONAL_SERVER
* @type JSON
* @param {String} APAC1 Value "sg"
* The option to select the Asia pacific server 1 regional server.
* @param {String} US1 Value "us2"
* The option to select the US server 1 regional server.
* @deprecated Signaling server selection is handled on
* the server side based on load and latency.
* @readOnly
* @component Room
* @for Skylink
* @since 0.5.0
*/
Skylink.prototype.REGIONAL_SERVER = {
APAC1: 'sg',
US1: 'us2'
};
/**
* The flag to enforce an SSL platform signaling and platform server connection.
* If self domain accessing protocol is https:, SSL connections
* would be automatically used. This flag is mostly used for self domain accessing protocol
* that is http: and enforcing the SSL connections for
* platform signaling and platform server connection.
* @attribute _forceSSL
* @type Boolean
* @default false
* @required
* @private
* @component Room
* @for Skylink
* @since 0.5.4
*/
Skylink.prototype._forceSSL = false;
/**
* The flag to enforce an SSL TURN server connection.
* If self domain accessing protocol is https:, SSL connections
* would be automatically used. This flag is mostly used for self domain accessing protocol
* that is http: and enforcing the SSL connections for
* TURN server connection.
* This will configure TURN server connection using port 443 only and
* if turns: protocol is supported, it will use turns: protocol.
* @attribute _forceTURNSSL
* @type Boolean
* @default false
* @required
* @private
* @component Room
* @for Skylink
* @since 0.6.1
*/
Skylink.prototype._forceTURNSSL = false;
/**
* The flag to enforce TURN server connection for quicker connectivity.
* @attribute _forceTURN
* @type Boolean
* @default false
* @required
* @private
* @component Room
* @for Skylink
* @since 0.6.1
*/
Skylink.prototype._forceTURN = false;
/**
* The constructed REST path that Skylink makes a HTTP /GET from
* to retrieve the connection information required.
* @attribute _path
* @type String
* @required
* @private
* @component Room
* @for Skylink
* @since 0.1.0
*/
Skylink.prototype._path = null;
/**
* The regional server that Skylink should connect to for fastest connectivity.
* @attribute _serverRegion
* @type String
* @private
* @component Room
* @for Skylink
* @since 0.5.0
*/
Skylink.prototype._serverRegion = null;
/**
* The platform server URL that Skylink can construct the REST path with to make
* a HTTP /GET to retrieve the connection information required.
* If the value is not the default value, it's mostly for debugging purposes.
* It's not advisable to allow developers to set the custom server URL unless
* they are aware of what they are doing, as this is a debugging feature.
* @attribute _roomServer
* @type String
* @default "//api.temasys.com.sg"
* @private
* @component Room
* @for Skylink
* @since 0.5.2
*/
Skylink.prototype._roomServer = '//api.temasys.com.sg';
/**
* Stores the Application Key that is configured in the
* {{#crossLink "Skylink/init:method"}}init(){{/crossLink}}.
* @attribute _appKey
* @type String
* @private
* @component Room
* @for Skylink
* @since 0.3.0
*/
Skylink.prototype._appKey = null;
/**
* Stores the default room that is configured in the
* {{#crossLink "Skylink/init:method"}}init(){{/crossLink}}.
* If no room is provided in {{#crossLink "Skylink/joinRoom:method"}}joinRoom(){{/crossLink}},
* this is the room that self would join to by default.
* If the value is not provided in {{#crossLink "Skylink/init:method"}}init(){{/crossLink}},
* by default, the value is the Application Key that is configured
* in {{#crossLink "Skylink/init:method"}}init(){{/crossLink}}.
* @attribute _defaultRoom
* @type String
* @default Skylink._appKey
* @private
* @component Room
* @for Skylink
* @since 0.3.0
*/
Skylink.prototype._defaultRoom = null;
/**
* Stores the new persistent room meeting start datetime stamp in
* [(ISO 8601 format)](https://en.wikipedia.org/wiki/ISO_8601).
* This will start a new meeting based on the starting datetime stamp
* in the room that was selected to join.
* The start date time of the room will not affect non persistent room connection.
* The persistent room feature is configurable in the Application Key
* in the developer console.
* @attribute _roomStart
* @type String
* @private
* @optional
* @component Room
* @for Skylink
* @since 0.3.0
*/
Skylink.prototype._roomStart = null;
/**
* Stores the new persistent room meeting duration (in hours)
* that the current new meeting duration should be in the room
* that was selected to join.
* The duration will not affect non persistent room connection.
* The persistent room feature is configurable in the Application Key
* in the developer console.
* @attribute _roomDuration
* @type Number
* @private
* @optional
* @component Room
* @for Skylink
* @since 0.3.0
*/
Skylink.prototype._roomDuration = null;
/**
* Stores the room credentials for Application Key.
* This is required for rooms connecting without CORS verification
* or starting a new persistent room meeting.
* To generate the credentials:
* - Concatenate a string that consists of the room name
* the room meeting duration (in hours) and the start date timestamp (in ISO 8601 format).
* Format room + duration + startDateTimeStamp.
* - Hash the concatenated string with the Application Key token using
* [SHA-1](https://en.wikipedia.org/wiki/SHA-1).
* You may use the [CryptoJS.HmacSHA1](https://code.google.com/p/crypto-js/#HMAC) function to do so.
* Example var hash = CryptoJS.HmacSHA1(concatenatedString, token);.
* - Convert the hash to a [Base64](https://en.wikipedia.org/wiki/Base64) encoded string. You may use the
* [CryptoJS.enc.Base64](https://code.google.com/p/crypto-js/#The_Cipher_Output) function
* to do so. Example var base64String = hash.toString(CryptoJS.enc.Base64); .
* - Encode the Base64 encoded string to a URI component using UTF-8 encoding with
* [encodeURIComponent()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent).
* Example var credentials = encodeURIComponent(base64String);
* and the duration.
* @attribute _roomCredentials
* @type String
* @private
* @optional
* @component Room
* @for Skylink
* @since 0.3.0
*/
Skylink.prototype._roomCredentials = null;
/**
* Stores the current Skylink room connection retrieval ready state.
* [Rel: Skylink.READY_STATE_CHANGE]
* @attribute _readyState
* @type Number
* @private
* @required
* @component Room
* @for Skylink
* @since 0.1.0
*/
Skylink.prototype._readyState = 0;
/**
* Stores the Skylink server connection key for the selected room.
* @attribute _key
* @type String
* @private
* @component Room
* @for Skylink
* @since 0.1.0
*/
Skylink.prototype._key = null;
/**
* Stores the Skylink server Application Key owner string for the selected room.
* @attribute _appKeyOwner
* @type String
* @private
* @component Room
* @for Skylink
* @since 0.5.2
*/
Skylink.prototype._appKeyOwner = null;
/**
* Stores the room connection information that is passed for starting
* the selected room connection. Some of these information are also
* used and required to send for every messages sent to the platform
* signaling connection for targeting the correct room and
* self identification in the room.
* @attribute _room
* @type JSON
* @param {String} id The room ID for identification to the platform signaling connection.
* @param {String} token The generated room token given by the platform server for starting
* the platform signaling connection.
* @param {String} startDateTime The start datetime stamp (in The startDateTime in
* [(ISO 8601 format)](https://en.wikipedia.org/wiki/ISO_8601) that the call has started
* sent by the platform server as an indication for the starting datetime of
* the platform signaling connection to self.
* @param {String} duration The duration of the room meeting (in hours). This duration will
* not affect non persistent room.
* @param {JSON} connection Connection The RTCPeerConnection constraints and configuration.
* @param {JSON} connection.peerConstraints Deprecated feature. The RTCPeerConnection
* constraints that is passed in this format new RTCPeerConnection(config, constraints);.
* This feature is not documented in W3C Specification draft and not advisable to use.
* @param {JSON} connection.peerConfig The RTCPeerConnection
* [RTCConfiguration](http://w3c.github.io/webrtc-pc/#idl-def-RTCConfiguration).
* @param {JSON} connection.offerConstraints Deprecated feature. The RTCPeerConnection
* [RTCOfferOptions](http://w3c.github.io/webrtc-pc/#idl-def-RTCOfferOptions) used in
* RTCPeerConnection.createOffer(successCb, failureCb, options);.
* @param {JSON} connection.sdpConstraints Not in use. The RTCPeerConnection
* [RTCAnswerOptions](http://w3c.github.io/webrtc-pc/#idl-def-RTCAnswerOptions) to be used
* in RTCPeerConnection.createAnswer(successCb, failureCb, options);.
* This is currently not in use due to not all browsers supporting this feature yet.
* @param {JSON} connection.mediaConstraints Deprecated feature. The getUserMedia()
* [MediaStreamConstraints](https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaStreamConstraints)
* in getUserMedia(constraints, successCb, failureCb);.
* @required
* @private
* @component Room
* @for Skylink
* @since 0.5.2
*/
Skylink.prototype._room = null;
/**
* Starts a HTTP /GET REST call to the platform server to
* retrieve the required connection information.
* @method _requestServerInfo
* @param {String} method The HTTP method. The value should be provided as
* "GET".
* @param {String} url The HTTP URI to invoke the REST call to. The
* value should be {{#crossLink "Skylink/_path:attribute"}}_path{{/crossLink}}.
* @param {Function} callback The callback fired The callback fired after the
* HTTP /GET REST call has a response from the platform server.
* @param {Number} callback.status The HTTP status code of the HTTP response
* given by the platform server.
* @param {JSON} callback.response The HTTP response data after the platform server
* has responded with the HTTP request.
* @param {Boolean} callback.response.success The response from the platform server
* if Application Key connection retrieval is successful and validated or not.
* @param {String} callback.response.pc_constraints For success state. The RTCPeerConnection
* constraints that would be configured in
* {{#crossLink "Skylink/_room:attribute"}}_room.peerConstraints{{/crossLink}} in
* {{#crossLink "Skylink/_parseInfo:method"}}_parseInfo(){{/crossLink}}.
* The data is in JSON stringified string and requires converting the JSON string
* to an JSON object to use the object.
* @param {String} callback.response.media_constraints For success state. The getUserMedia()
* MediaStreamConstraints that would be configured in
* {{#crossLink "Skylink/_room:attribute"}}_room.mediaConstraints{{/crossLink}} in
* {{#crossLink "Skylink/_parseInfo:method"}}_parseInfo(){{/crossLink}}.
* The data is in JSON stringified string and requires converting the JSON string
* to an JSON object to use the object.
* @param {String} callback.response.offer_constraints For success state. The RTCPeerConnection
* RTCOfferOptions that would be configured in
* {{#crossLink "Skylink/_room:attribute"}}_room.offerConstraints{{/crossLink}} in
* {{#crossLink "Skylink/_parseInfo:method"}}_parseInfo(){{/crossLink}}.
* The data is in JSON stringified string and requires converting the JSON string
* to an JSON object to use the object.
* @param {String} callback.response.bandwidth For success state. The self
* streaming bandwidth settings. Setting the bandwidth flags may not
* force set the bandwidth for each connection stream channels as it depends
* on how the browser handles the bandwidth bitrate. Values are configured
* in <var>kb/s</var>.
* @param {String} callback.response.bandwidth.audio The default
* audio stream channel for self Stream object bandwidth
* that audio streaming should use in <var>kb/s</var>.
* @param {String} callback.response.bandwidth.video The default
* video stream channel for self Stream object bandwidth
* that video streaming should use in <var>kb/s</var>.
* @param {String} callback.response.bandwidth.data The default
* datachannel channel for the DataChannel connection bandwidth
* that datachannel connection per packet should be able use in <var>kb/s</var>.
* @param {String} callback.response.cid For success state. The Skylink server connection key for the
* selected room. This would be stored in {{#crossLink "Skylink/_key:attribute"}}_key{{/crossLink}}
* in {{#crossLink "Skylink/_parseInfo:method"}}_parseInfo(){{/crossLink}}.
* @param {String} callback.response.apiOwner For success state. The Skylink server Application
* Key owner string for the selected room. This would be stored in
* {{#crossLink "Skylink/_appKeyOwner:attribute"}}_appKeyOwner{{/crossLink}}
* in {{#crossLink "Skylink/_parseInfo:method"}}_parseInfo(){{/crossLink}}.
* @param {Array} callback.response.httpPortList For success state. The list of HTTP
* ports for reconnection retries. This would be stored in
* {{#crossLink "Skylink/_socketPorts:attribute"}}_socketPorts.http:{{/crossLink}}.
* @param {Number} callback.response.httpPortList.(#index) The HTTP port that Skylink
* could reattempt to establish for a signaling connection with http: protocol.
* @param {Array} callback.response.httpsPortList For success state. The list of HTTPS
* ports for reconnection retries. This would be stored in
* {{#crossLink "Skylink/_socketPorts:attribute"}}_socketPorts.https:{{/crossLink}}.
* @param {Number} callback.response.httpsPortList.(#index) The HTTPS port that Skylink
* could reattempt to establish for a signaling connection with https: protocol or
* when {{#crossLink "Skylink/_forceSSL:attribute"}}_forceSSL{{/crossLink}} is enabled.
* @param {String} callback.response.ipSigserver For success state. The platform signaling endpoint URI
* to open socket connection with. This would be stored in
* {{#crossLink "Skylink/_signalingServer:attribute"}}_signalingServer{{/crossLink}}.
* @param {String} callback.response.roomCred For success state. The generated room token given
* by the platform server for starting the platform signaling connection. This would be stored in
* {{#crossLink "Skylink/_room:attribute"}}_room.token{{/crossLink}}.
* @param {String} callback.response.room_key For success state. The room ID for identification
* to the platform signaling connection. This would be stored in
* {{#crossLink "Skylink/_room:attribute"}}_room.id{{/crossLink}}.
* @param {String} callback.response.start For success state. The start datetime stamp (in The startDateTime in
* [(ISO 8601 format)](https://en.wikipedia.org/wiki/ISO_8601) that the call has started
* sent by the platform server as an indication for the starting datetime of
* the platform signaling connection to self. This would be stored in
* {{#crossLink "Skylink/_room:attribute"}}_room.startDateTime{{/crossLink}}.
* @param {String} callback.response.timeStamp For success state. The self session timestamp.
* This would be stored in {{#crossLink "Skylink/_user:attribute"}}_user.timeStamp{{/crossLink}}
* @param {String} callback.response.userCred For success state. The self session access token.
* This would be stored in {{#crossLink "Skylink/_user:attribute"}}_user.token{{/crossLink}}.
* @param {String} callback.response.username For success state. The self session ID.
* This would be stored in {{#crossLink "Skylink/_user:attribute"}}_user.username{{/crossLink}}.
* @param {String} callback.response.info For failure state. The error message thrown by
* the platform server.
* @param {Number} callback.response.error For failure state. The error code of the error thrown by
* the platform server.
* @param {JSON} params HTTP Params The HTTP data parameters that would be
* application/json;charset=UTF-8 encoded when sent to the
* platform server.
* @private
* @component Room
* @for Skylink
* @since 0.5.2
*/
Skylink.prototype._requestServerInfo = function(method, url, callback, params) {
var self = this;
// XDomainRequest is supported in IE8 - 9
var useXDomainRequest = typeof window.XDomainRequest === 'function' ||
typeof window.XDomainRequest === 'object';
self._socketUseXDR = useXDomainRequest;
var xhr;
// set force SSL option
url = (self._forceSSL) ? 'https:' + url : url;
if (useXDomainRequest) {
log.debug([null, 'XMLHttpRequest', method, 'Using XDomainRequest. ' +
'XMLHttpRequest is now XDomainRequest'], {
agent: window.webrtcDetectedBrowser,
version: window.webrtcDetectedVersion
});
xhr = new XDomainRequest();
xhr.setContentType = function (contentType) {
xhr.contentType = contentType;
};
} else {
log.debug([null, 'XMLHttpRequest', method, 'Using XMLHttpRequest'], {
agent: window.webrtcDetectedBrowser,
version: window.webrtcDetectedVersion
});
xhr = new window.XMLHttpRequest();
xhr.setContentType = function (contentType) {
xhr.setRequestHeader('Content-type', contentType);
};
}
xhr.onload = function () {
var response = xhr.responseText || xhr.response;
var status = xhr.status || 200;
log.debug([null, 'XMLHttpRequest', method, 'Received sessions parameters'],
JSON.parse(response || '{}'));
callback(status, JSON.parse(response || '{}'));
};
xhr.onerror = function (error) {
log.error([null, 'XMLHttpRequest', method, 'Failed retrieving information:'],
{ status: xhr.status });
self._readyState = -1;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: xhr.status || null,
content: 'Network error occurred. (Status: ' + xhr.status + ')',
errorCode: self.READY_STATE_CHANGE_ERROR.XML_HTTP_REQUEST_ERROR
}, self._selectedRoom);
};
xhr.onprogress = function () {
log.debug([null, 'XMLHttpRequest', method,
'Retrieving information and config from webserver. Url:'], url);
log.debug([null, 'XMLHttpRequest', method, 'Provided parameters:'], params);
};
xhr.open(method, url, true);
if (params) {
xhr.setContentType('application/json;charset=UTF-8');
xhr.send(JSON.stringify(params));
} else {
xhr.send();
}
};
/**
* Parses the connection information retrieved from the platform server and
* stores them into the relevant attributes in
* {{#crossLink "Skylink/_room:attribute"}}_room{{/crossLink}} and
* {{#crossLink "Skylink/_user:attribute"}}_user{{/crossLink}}.
* @method _parseInfo
* @param {JSON} info The HTTP response data if the HTTP status
* code is 200 (which means <var>HTTP OK</var> code)
* @param {String} info.pc_constraints The RTCPeerConnection constraints.
* The data is in JSON stringified string and requires converting the JSON string
* to an JSON object to use the object.
* @param {String} info.media_constraints The getUserMedia() MediaStreamConstraints.
* The data is in JSON stringified string and requires converting the JSON string
* to an JSON object to use the object.
* @param {String} info.offer_constraints The RTCPeerConnection RTCOfferOptions.
* The data is in JSON stringified string and requires converting the JSON string
* to an JSON object to use the object.
* @param {String} info.bandwidth The self
* streaming bandwidth settings. Setting the bandwidth flags may not
* force set the bandwidth for each connection stream channels as it depends
* on how the browser handles the bandwidth bitrate. Values are configured
* in <var>kb/s</var>.
* @param {String} info.bandwidth.audio The default
* audio stream channel for self Stream object bandwidth
* that audio streaming should use in <var>kb/s</var>.
* @param {String} info.bandwidth.video The default
* video stream channel for self Stream object bandwidth
* that video streaming should use in <var>kb/s</var>.
* @param {String} info.bandwidth.data The default
* datachannel channel for the DataChannel connection bandwidth
* that datachannel connection per packet should be able use in <var>kb/s</var>.
* @param {String} info.cid The Skylink server connection key for starting the
* selected room connection.
* @param {String} info.apiOwner The Skylink server Application Key owner string for the selected room.
* @param {Array} info.httpPortList The list of HTTP
* ports for reconnection retries.
* @param {Number} info.httpPortList.(#index) The HTTP port that Skylink
* could reattempt to establish for a signaling connection with http: protocol.
* @param {Array} info.httpsPortList The list of HTTPS
* ports for reconnection retries.
* @param {Number} info.httpsPortList.(#index) The HTTPS port that Skylink
* could reattempt to establish for a signaling connection with https: protocol or
* when {{#crossLink "Skylink/_forceSSL:attribute"}}_forceSSL{{/crossLink}} is enabled.
* @param {String} info.ipSigserver The platform signaling endpoint URI
* to open socket connection with.
* @param {String} info.roomCred The generated room token given
* by the platform server for starting the platform signaling connection.
* @param {String} info.room_key For success state. The room ID for identification
* to the platform signaling connection.
* @param {String} info.start The start datetime stamp (in The startDateTime in
* [(ISO 8601 format)](https://en.wikipedia.org/wiki/ISO_8601) that the call has started
* sent by the platform server as an indication for the starting datetime of
* the platform signaling connection to self.
* @param {String} info.timeStamp The self session timestamp.
* @param {String} info.userCred The self session access token.
* @param {String} info.username The self session ID.
* @trigger readyStateChange
* @private
* @required
* @component Room
* @for Skylink
* @since 0.5.2
*/
Skylink.prototype._parseInfo = function(info) {
log.log('Parsing parameter from server', info);
if (!info.pc_constraints && !info.offer_constraints) {
this._trigger('readyStateChange', this.READY_STATE_CHANGE.ERROR, {
status: 200,
content: info.info,
errorCode: info.error
}, self._selectedRoom);
return;
}
log.debug('Peer connection constraints:', info.pc_constraints);
log.debug('Offer constraints:', info.offer_constraints);
this._key = info.cid;
this._appKeyOwner = info.apiOwner;
this._signalingServer = info.ipSigserver;
this._isPrivileged = info.isPrivileged;
this._autoIntroduce = info.autoIntroduce;
this._parentKey = info.room_key.substring(0,36);
this._user = {
uid: info.username,
token: info.userCred,
timeStamp: info.timeStamp,
streams: [],
info: {}
};
this._room = {
id: info.room_key,
token: info.roomCred,
startDateTime: info.start,
duration: info.len,
connection: {
peerConstraints: JSON.parse(info.pc_constraints),
peerConfig: null,
offerConstraints: JSON.parse(info.offer_constraints),
sdpConstraints: {
mandatory: {
OfferToReceiveAudio: true,
OfferToReceiveVideo: true
}
},
mediaConstraints: JSON.parse(info.media_constraints)
}
};
this._parseDefaultMediaStreamSettings(this._room.connection.mediaConstraints);
// set the socket ports
this._socketPorts = {
'http:': info.httpPortList,
'https:': info.httpsPortList
};
// use default bandwidth and media resolution provided by server
//this._streamSettings.bandwidth = info.bandwidth;
//this._streamSettings.video = info.video;
this._readyState = 2;
this._trigger('readyStateChange', this.READY_STATE_CHANGE.COMPLETED, null, this._selectedRoom);
log.info('Parsed parameters from webserver. ' +
'Ready for web-realtime communication');
};
/**
* Starts loading the required dependencies and then retrieve the required
* connection information from the platform server.
* @method _loadInfo
* @trigger readyStateChange
* @private
* @required
* @component Room
* @for Skylink
* @since 0.5.2
*/
Skylink.prototype._loadInfo = function() {
var self = this;
// check if adapterjs has been loaded already first or not
var adapter = (function () {
try {
return window.AdapterJS || AdapterJS;
} catch (error) {
return false;
}
})();
if (!(!!adapter ? typeof adapter.webRTCReady === 'function' : false)) {
var noAdapterErrorMsg = 'AdapterJS dependency is not loaded or incorrect AdapterJS dependency is used';
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: null,
content: noAdapterErrorMsg,
errorCode: self.READY_STATE_CHANGE_ERROR.ADAPTER_NO_LOADED
}, self._selectedRoom);
return;
}
if (!window.io) {
log.error('Socket.io not loaded. Please load socket.io');
self._readyState = -1;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: null,
content: 'Socket.io not found',
errorCode: self.READY_STATE_CHANGE_ERROR.NO_SOCKET_IO
}, self._selectedRoom);
return;
}
if (!window.XMLHttpRequest) {
log.error('XMLHttpRequest not supported. Please upgrade your browser');
self._readyState = -1;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: null,
content: 'XMLHttpRequest not available',
errorCode: self.READY_STATE_CHANGE_ERROR.NO_XMLHTTPREQUEST_SUPPORT
}, self._selectedRoom);
return;
}
if (!window.RTCPeerConnection) {
log.error('WebRTC not supported. Please upgrade your browser');
self._readyState = -1;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: null,
content: 'WebRTC not available',
errorCode: self.READY_STATE_CHANGE_ERROR.NO_WEBRTC_SUPPORT
}, self._selectedRoom);
return;
}
if (!self._path) {
log.error('Skylink is not initialised. Please call init() first');
self._readyState = -1;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: null,
content: 'No API Path is found',
errorCode: self.READY_STATE_CHANGE_ERROR.NO_PATH
}, self._selectedRoom);
return;
}
adapter.webRTCReady(function () {
self._readyState = 1;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.LOADING, null, self._selectedRoom);
self._requestServerInfo('GET', self._path, function(status, response) {
if (status !== 200) {
// 403 - Room is locked
// 401 - API Not authorized
// 402 - run out of credits
var errorMessage = 'XMLHttpRequest status not OK\nStatus was: ' + status;
self._readyState = 0;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.ERROR, {
status: status,
content: (response) ? (response.info || errorMessage) : errorMessage,
errorCode: response.error ||
self.READY_STATE_CHANGE_ERROR.INVALID_XMLHTTPREQUEST_STATUS
}, self._selectedRoom);
return;
}
self._parseInfo(response);
});
});
};
/**
* Starts loading the required connection information to start connection
* based on the selected room in {{#crossLink "Skylink/joinRoom:method"}}joinRoom(){{/crossLink}}.
* @method _initSelectedRoom
* @param {String} [room] The room to retrieve required connection information
* to start connection. If room is not provided, the room
* would default to the the defaultRoom option set
* in {{#crossLink "Skylink/init:method"}}init() settings{{/crossLink}}.
* @param {Function} callback The callback fired after required connection
* information has been retrieved successfully with the provided media
* settings or have met with an exception.
* @param {Object} callback.error The error object received in the callback.
* If received as null, it means that there is no errors.
* @trigger readyStateChange
* @private
* @component Room
* @for Skylink
* @since 0.5.5
*/
Skylink.prototype._initSelectedRoom = function(room, callback) {
var self = this;
if (typeof room === 'function' || typeof room === 'undefined') {
log.error('Invalid room provided. Room:', room);
return;
}
var defaultRoom = self._defaultRoom;
var initOptions = {
roomServer: self._roomServer,
defaultRoom: room || defaultRoom,
appKey: self._appKey,
region: self._serverRegion,
enableDataChannel: self._enableDataChannel,
enableIceTrickle: self._enableIceTrickle
};
if (self._roomCredentials) {
initOptions.credentials = {
credentials: self._roomCredentials,
duration: self._roomDuration,
startDateTime: self._roomStart
};
}
self.init(initOptions, function (error, success) {
self._defaultRoom = defaultRoom;
if (error) {
callback(error);
} else {
callback(null);
}
});
};
/**
* Initialises and configures Skylink to begin any connection.
* NOTE that this is the first method that has to be called before
* using any other functionalities other than debugging features like
* {{#crossLink "Skylink/setLogLevel:method"}}setLogLevel(){{/crossLink}} and
* {{#crossLink "Skylink/setDebugMode:method"}}setDebugMode(){{/crossLink}} and
* after all event subscriptions like {{#crossLink "Skylink/on:method"}}on(){{/crossLink}}
* or {{#crossLink "Skylink/once:method"}}once(){{/crossLink}} has been made.
* This is where the Application Key is configured and attached to Skylink for usage.
* @method init
* @param {String|JSON} options The configuration settings for Skylink.
* If provided options is a <var>typeof</var> string, it will
* be interpreted as the Application Key being provided.
* @param {String} options.appKey Previously known as apiKey.
* The Application Key that Skylink uses for initialising and connecting rooms.
* @param {String} [options.defaultRoom=options.appKey] The default room that
* Skylink should connect to if there is no room provided in
* {{#crossLink "Skylink/joinRoom:method"}}joinRoom(){{/crossLink}}.
* If this value is not provided, the default room value would be
* the Application Key provided.
* @param {String} [options.roomServer] The platform server URL that Skylink makes a
* HTTP /GET to retrieve the connection information required.
* This is a debugging feature, and it's not advisable to manipulate
* this value unless you are using a beta platform server.
* @param {String} [options.region] Deprecated feature. The regional server that Skylink
* should connect to for fastest connectivity. [Rel: Skylink.REGIONAL_SERVER]
* @param {Boolean} [options.enableIceTrickle=true] Debugging Feature.
* The flag that indicates if PeerConnections
* should enable trickling of ICE to connect the ICE connection. Configuring
* this value to false may result in a slower connection but
* a more stable connection.
* @param {Boolean} [options.enableDataChannel=true] Debugging feature.
* The flag that indicates if PeerConnections
* should have any DataChannel connections. Configuring this value to false
* may result in failure to use features like
* {{#crossLink "Skylink/sendBlobData:method"}}sendBlobData(){{/crossLink}},
* {{#crossLink "Skylink/sendP2PMessage:method"}}sendP2PMessage(){{/crossLink}} and
* {{#crossLink "Skylink/sendURLData:method"}}sendURLData(){{/crossLink}} or any
* DataChannel connection related services.
* @param {Boolean} [options.enableTURNServer=true] Debugging feature.
* The flag that indicates if PeerConnections connection should use any TURN server connection.
* Tampering this flag may disable any successful Peer connection
* that is behind any firewalls, so set this value at your own risk.
* @param {Boolean} [options.enableSTUNServer=true] Debugging feature.
* The flag that indicates if PeerConnections connection should use any STUN server connection.
* Tampering this flag may cause issues to connections, so set this value at your own risk.
* @param {Boolean} [options.forceTURN=false] The flag that indicates if PeerConnections connection
* should only use TURN server connection which enables a quicker connectivity.
* This configuration will override the settings for enableTURNServer
* and enableSTUNServer and set enableTURNServer as true and
* enableSTUNServer as false if the value is set to true.
* @param {Boolean} [options.usePublicSTUN=true] The flag that indicates if PeerConnections connection
* should enable usage of public STUN server connection connectivity.
* This configuration would not work if enableSTUNServer is set to false
* or forceTURN is set to true.
* @param {Boolean} [options.TURNServerTransport=Skylink.TURN_TRANSPORT.ANY] Debugging feature.
* The TURN server transport to enable for TURN server connections.
* Tampering this flag may cause issues to connections, so set this value at your own risk.
* [Rel: Skylink.TURN_TRANSPORT]
* @param {JSON} [options.credentials] The credentials configured for starting a new persistent
* room meeting or connecting with Application Keys that do not use CORS authentication.
* Setting the startDateTime or the duration will not affect
* the actual duration for non persistent rooms. This feature would only affect connections with
* Application Keys that is configured for persistent room feature.
* To enable persistent room or disable CORS, you may set it in the developer console.
* CORS may be disabled by setting the platform to "Other".
* @param {String} options.credentials.startDateTime The room start datetime stamp in
* ISO 8601 format.
* This will start a new meeting based on the starting datetime stamp
* in the room that was selected to join for Application Key that is configured
* with persistent room feature. You may use
*
* Date.toISOString() to retrieve ISO 8601 formatted date time stamp.
* The start date time of the room will not affect non persistent room connection.
* @param {Number} options.credentials.duration The duration (in hours)
* that the room duration should be in. This will set the duration starting from
* the provided startDateTime onwards and after the duration is over,
* the meeting is over and the room is closed for Application Key that is
* configured with persistent room feature.
* The duration will not affect non persistent room connection.The duration of the meeting in hours.

* E.g. 0.5 for half an hour, 1.4 for 1 hour and 24 minutes
* @param {String} options.credentials.credentials The room credentials for Application Key.
* This is required for rooms connecting without CORS verification or starting a new persistent room meeting.

* To generate the credentials:

*

*
Concatenate a string that consists of the room name
* the room meeting duration (in hours) and the start date timestamp (in ISO 8601 format).

* Format room + "_" + duration + "_" + startDateTimeStamp

*
Hash the concatenated string with the Application Key token using
* SHA-1.
* You may use the CryptoJS.HmacSHA1 function to do so.

* Example var hash = CryptoJS.HmacSHA1(concatenatedString, token);

*
Convert the hash to a Base64 encoded string. You may use the
* CryptoJS.enc.Base64 function
* to do so.
Example var base64String = hash.toString(CryptoJS.enc.Base64);

*
Encode the Base64 encoded string to a URI component using UTF-8 encoding with
* encodeURIComponent().

* Example var credentials = encodeURIComponent(base64String);

*

* @param {Boolean} [options.audioFallback=false] The flag that indicates if there is a failure in
* {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}} in retrieving user media
* video stream, it should fallback to retrieve audio stream only. This would not work for
* {{#crossLink "Skylink/joinRoom:method"}}joinRoom(){{/crossLink}} except
* {{#crossLink "Skylink/getUserMedia:method"}}getUserMedia(){{/crossLink}}.
* @param {Boolean} [options.forceSSL=false] The flag to enforce an SSL platform signaling and platform server connection.
* If self domain accessing protocol is https:, SSL connections
* would be automatically used. This flag is mostly used for self domain accessing protocol
* that is http: and enforcing the SSL connections for
* platform signaling and platform server connection.
* @param {String} [options.audioCodec=Skylink.AUDIO_CODEC.AUTO] Debugging Feature.
* The preferred audio codec that Peer connection
* streaming audio codec should use in the connection when available. If not available, the default
* codec would be the browser generated session description selected codec. [Rel: Skylink.AUDIO_CODEC]
* @param {String} [options.videoCodec=Skylink.VIDEO_CODEC.AUTO] Debugging Feature.
* The preferred video codec that Peer connection
* streaming video codec should use in the connection when available. If not available, the default
* codec would be the browser generated session description selected codec. [Rel: Skylink.VIDEO_CODEC]
* @param {Number} [options.socketTimeout=20000] The timeout that the socket connection should throw a
* timeout exception when socket fails to receive a response from connection. Depending on
* the max retries left based on the availability of ports given by the platform server,
* the socket will reattempt to establish a socket connection with the signaling server.

* The mininum timeout value is 5000.
* @param {Boolean} [options.forceTURNSSL=false] The flag to enforce an SSL TURN server connection.
* If self domain accessing protocol is https:, SSL connections
* would be automatically used. This flag is mostly used for self domain accessing protocol
* that is http: and enforcing the SSL connections for
* TURN server connection.
* This will configure TURN server connection using port 443 only and
* if turns: protocol is supported, it will use turns: protocol.
* @param {Function} [callback] The callback fired after Skylink has been
* initialised successfully or have met with an exception.
* The callback signature is function (error, success).
* @param {JSON} callback.error The error object received in the callback.
* If received as null, it means that there is no errors.
* @param {Number} callback.error.errorCode The
* READY_STATE_CHANGE_ERROR
* if there is an readyStateChange
* event error that caused the failure for initialising Skylink.
* [Rel: Skylink.READY_STATE_CHANGE_ERROR]
* @param {Object} callback.error.error The exception thrown that caused the failure
* for initialising Skylink.
* @param {Number} callback.error.status The XMLHttpRequest status code received
* when exception is thrown that caused the failure for initialising Skylink.
* @param {JSON} callback.success The success object received in the callback.
* If received as null, it means that there are errors.
* @param {String} callback.success.appKey Previously known as apiKey.
* The Application Key that Skylink uses for initialising and connecting rooms.
* @param {String} callback.success.defaultRoom The default room that
* Skylink should connect to if there is no room provided in
* joinRoom().
* @param {String} callback.success.roomServer The platform server URL that Skylink makes a
* HTTP /GET to retrieve the connection information required.
* @param {Boolean} callback.success.enableIceTrickle The flag that indicates if PeerConnections
* should enable trickling of ICE to connect the ICE connection.
* @param {Boolean} callback.success.enableDataChannel The flag that indicates if PeerConnections
* should have any DataChannel connections.
* @param {Boolean} callback.success.enableTURNServer The flag that indicates if
* PeerConnections connection should use any TURN server connection.
* @param {Boolean} callback.success.enableSTUNServer The flag that indicates if
* PeerConnections connection should use any STUN server connection.
* @param {Boolean} callback.success.TURNServerTransport The TURN server transport
* to enable for TURN server connections.
* [Rel: Skylink.TURN_TRANSPORT]
* @param {String} [callback.success.serverRegion] The regional server that Skylink
* should connect to for fastest connectivity. [Rel: Skylink.REGIONAL_SERVER]
* @param {Boolean} callback.success.audioFallback The flag that indicates if there is a failure in
* getUserMedia() in retrieving user media
* video stream, it should fallback to retrieve audio stream only.
* @param {Boolean} callback.success.forceSSL The flag to enforce an SSL platform signaling and platform server connection.
* If self domain accessing protocol is https:, SSL connections
* would be automatically used.
* @param {String} callback.success.audioCodec The preferred audio codec that Peer connection
* streaming audio codec should use in the connection when available. [Rel: Skylink.AUDIO_CODEC]
* @param {String} callback.success.videoCodec The preferred video codec that Peer connection
* streaming video codec should use in the connection when available. [Rel: Skylink.VIDEO_CODEC]
* @param {Number} callback.success.socketTimeout The timeout that the socket connection should throw a
* timeout exception when socket fails to receive a response from connection. Depending on
* the max retries left based on the availability of ports given by the platform server,
* the socket will reattempt to establish a socket connection with the signaling server.
* @param {Boolean} callback.success.forceTURNSSL The flag to enforce an SSL TURN server connection.
* If self domain accessing protocol is https:, SSL connections
* would be automatically used.
* This will configure TURN server connection using port 443 only and
* if turns: protocol is supported, it will use turns: protocol.
* @param {Boolean} callback.success.forceTURN The flag that indicates if PeerConnections connection
* should only use TURN server connection which enables a quicker connectivity.
* This configuration will override the settings for enableTURNServer
* and enableSTUNServer and set enableTURNServer as true and
* enableSTUNServer as false if the value is set to true.
* @param {Boolean} callback.success.usePublicSTUN The flag that indicates if PeerConnections connection
* should enable usage of public STUN server connection connectivity.
* This configuration would not work if enableSTUNServer is set to false
* or forceTURN is set to true.
* @example
* // Note: Default room is appKey when no room
* // Example 1: To initalize without setting any default room.
* SkylinkDemo.init("YOUR_APP_KEY_HERE");
*
* // Example 2: To initialize with appKey and defaultRoom
* SkylinkDemo.init({
* appKey: "YOUR_APP_KEY_HERE",
* defaultRoom: "mainHangout"
* });
*
* // Example 3: To initialize with credentials to set startDateTime and
* // duration of the room
* var hash = CryptoJS.HmacSHA1(roomname + "_" + duration + "_" +
* (new Date()).toISOString(), token);
* var credentials = encodeURIComponent(hash.toString(CryptoJS.enc.Base64));
* SkylinkDemo.init({
* appKey: "YOUR_APP_KEY_HERE",
* defaultRoom: "mainHangout"
* credentials: {
* startDateTime: (new Date()).toISOString(),
* duration: 500,
* credentials: credentials
* }
* });
*
* // Example 4: To initialize with callback
* SkylinkDemo.init("YOUR_APP_KEY_HERE", function(error,success){
* if (error){
* console.error("Init failed:", error);
* }
* else{
* console.info("Init succeed:", success);
* }
* });
*
* @trigger readyStateChange
* @required
* @component Room
* @for Skylink
* @since 0.5.5
*/
Skylink.prototype.init = function(options, callback) {
var self = this;
if (typeof options === 'function'){
callback = options;
options = undefined;
}
if (!options) {
var error = 'No API key provided';
log.error(error);
if (typeof callback === 'function'){
callback(error,null);
}
return;
}
var appKey, room, defaultRoom, region;
var startDateTime, duration, credentials;
var roomServer = self._roomServer;
// NOTE: Should we get all the default values from the variables
// rather than setting it?
var enableIceTrickle = true;
var enableDataChannel = true;
var enableSTUNServer = true;
var enableTURNServer = true;
var TURNTransport = self.TURN_TRANSPORT.ANY;
var audioFallback = false;
var forceSSL = false;
var socketTimeout = 0;
var forceTURNSSL = false;
var audioCodec = self.AUDIO_CODEC.AUTO;
var videoCodec = self.VIDEO_CODEC.AUTO;
var forceTURN = false;
var usePublicSTUN = true;
log.log('Provided init options:', options);
if (typeof options === 'string') {
// set all the default api key, default room and room
appKey = options;
defaultRoom = appKey;
room = appKey;
} else {
// set the api key
appKey = options.appKey || options.apiKey;
// set the room server
roomServer = options.roomServer || roomServer;
// check room server if it ends with /. Remove the extra /
roomServer = (roomServer.lastIndexOf('/') ===
(roomServer.length - 1)) ? roomServer.substring(0,
roomServer.length - 1) : roomServer;
// set the region
region = options.region || region;
// set the default room
defaultRoom = options.defaultRoom || appKey;
// set the selected room
room = defaultRoom;
// set ice trickle option
enableIceTrickle = (typeof options.enableIceTrickle === 'boolean') ?
options.enableIceTrickle : enableIceTrickle;
// set data channel option
enableDataChannel = (typeof options.enableDataChannel === 'boolean') ?
options.enableDataChannel : enableDataChannel;
// set stun server option
enableSTUNServer = (typeof options.enableSTUNServer === 'boolean') ?
options.enableSTUNServer : enableSTUNServer;
// set turn server option
enableTURNServer = (typeof options.enableTURNServer === 'boolean') ?
options.enableTURNServer : enableTURNServer;
// set the force ssl always option
forceSSL = (typeof options.forceSSL === 'boolean') ?
options.forceSSL : forceSSL;
// set the socket timeout option
socketTimeout = (typeof options.socketTimeout === 'number') ?
options.socketTimeout : socketTimeout;
// set the socket timeout option to be above 5000
socketTimeout = (socketTimeout < 5000) ? 5000 : socketTimeout;
// set the force turn ssl always option
forceTURNSSL = (typeof options.forceTURNSSL === 'boolean') ?
options.forceTURNSSL : forceTURNSSL;
// set the preferred audio codec
audioCodec = typeof options.audioCodec === 'string' ?
options.audioCodec : audioCodec;
// set the preferred video codec
videoCodec = typeof options.videoCodec === 'string' ?
options.videoCodec : videoCodec;
// set the force turn server option
forceTURN = (typeof options.forceTURN === 'boolean') ?
options.forceTURN : forceTURN;
// set the use public stun option
usePublicSTUN = (typeof options.usePublicSTUN === 'boolean') ?
options.usePublicSTUN : usePublicSTUN;
// set turn transport option
if (typeof options.TURNServerTransport === 'string') {
// loop out for every transport option
for (var type in self.TURN_TRANSPORT) {
if (self.TURN_TRANSPORT.hasOwnProperty(type)) {
// do a check if the transport option is valid
if (self.TURN_TRANSPORT[type] === options.TURNServerTransport) {
TURNTransport = options.TURNServerTransport;
break;
}
}
}
}
// set audio fallback option
audioFallback = options.audioFallback || audioFallback;
// Custom default meeting timing and duration
// Fallback to default if no duration or startDateTime provided
if (options.credentials) {
// set start data time
startDateTime = options.credentials.startDateTime ||
(new Date()).toISOString();
// set the duration
duration = options.credentials.duration || 200;
// set the credentials
credentials = options.credentials.credentials;
}
// if force turn option is set to on
if (forceTURN === true) {
enableTURNServer = true;
enableSTUNServer = false;
}
}
// api key path options
self._appKey = appKey;
self._roomServer = roomServer;
self._defaultRoom = defaultRoom;
self._selectedRoom = room;
self._serverRegion = region || null;
self._path = roomServer + '/api/' + appKey + '/' + room;
// set credentials if there is
if (credentials) {
self._roomStart = startDateTime;
self._roomDuration = duration;
self._roomCredentials = credentials;
self._path += (credentials) ? ('/' + startDateTime + '/' +
duration + '?&cred=' + credentials) : '';
}
self._path += ((credentials) ? '&' : '?') + 'rand=' + (new Date()).toISOString();
// check if there is a other query parameters or not
if (region) {
self._path += '&rg=' + region;
}
// skylink functionality options
self._enableIceTrickle = enableIceTrickle;
self._enableDataChannel = enableDataChannel;
self._enableSTUN = enableSTUNServer;
self._enableTURN = enableTURNServer;
self._TURNTransport = TURNTransport;
self._audioFallback = audioFallback;
self._forceSSL = forceSSL;
self._socketTimeout = socketTimeout;
self._forceTURNSSL = forceTURNSSL;
self._selectedAudioCodec = audioCodec;
self._selectedVideoCodec = videoCodec;
self._forceTURN = forceTURN;
self._usePublicSTUN = usePublicSTUN;
log.log('Init configuration:', {
serverUrl: self._path,
readyState: self._readyState,
appKey: self._appKey,
roomServer: self._roomServer,
defaultRoom: self._defaultRoom,
selectedRoom: self._selectedRoom,
serverRegion: self._serverRegion,
enableDataChannel: self._enableDataChannel,
enableIceTrickle: self._enableIceTrickle,
enableTURNServer: self._enableTURN,
enableSTUNServer: self._enableSTUN,
TURNTransport: self._TURNTransport,
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
forceTURN: self._forceTURN,
usePublicSTUN: self._usePublicSTUN
});
// trigger the readystate
self._readyState = 0;
self._trigger('readyStateChange', self.READY_STATE_CHANGE.INIT, null, self._selectedRoom);
if (typeof callback === 'function'){
var hasTriggered = false;
var readyStateChangeFn = function (readyState, error) {
if (!hasTriggered) {
if (readyState === self.READY_STATE_CHANGE.COMPLETED) {
log.log([null, 'Socket', null, 'Firing callback. ' +
'Ready state change has met provided state ->'], readyState);
hasTriggered = true;
self.off('readyStateChange', readyStateChangeFn);
callback(null,{
serverUrl: self._path,
readyState: self._readyState,
appKey: self._appKey,
roomServer: self._roomServer,
defaultRoom: self._defaultRoom,
selectedRoom: self._selectedRoom,
serverRegion: self._serverRegion,
enableDataChannel: self._enableDataChannel,
enableIceTrickle: self._enableIceTrickle,
enableTURNServer: self._enableTURN,
enableSTUNServer: self._enableSTUN,
TURNTransport: self._TURNTransport,
audioFallback: self._audioFallback,
forceSSL: self._forceSSL,
socketTimeout: self._socketTimeout,
forceTURNSSL: self._forceTURNSSL,
audioCodec: self._selectedAudioCodec,
videoCodec: self._selectedVideoCodec,
forceTURN: self._forceTURN,
usePublicSTUN: self._usePublicSTUN
});
} else if (readyState === self.READY_STATE_CHANGE.ERROR) {
log.log([null, 'Socket', null, 'Firing callback. ' +
'Ready state change has met provided state ->'], readyState);
log.debug([null, 'Socket', null, 'Ready state met failure'], error);
hasTriggered = true;
self.off('readyStateChange', readyStateChangeFn);
callback({
error: new Error(error),
errorCode: error.errorCode,
status: error.status
},null);
}
}
};
self.on('readyStateChange', readyStateChangeFn);
}
self._loadInfo();
};


Future
It's possible to constructe HTML pages + vue-github components to dynamically represent the state of a "roadmap" as seen across multiple GitHub projects (aka repos).
All the open milestones from {{user}} / {{project}} + their
descriptions which may include vue-github markup for issue lists from
other repositories. Sadly, there are only two sort options:
due_date
and completeness
.
This milestone is chosen entirely via markup and could be from any public GitHub repo. It also includes the "embeded" markup from the description of this milestone (if present).
Also completely declared via markup and with it's output build from a custom template partial.


This module will benefit developers. Standard CMSMS installations will NOT benefit from this, as standard CMSMS logs will not go to Monolog.
Integrates https://github.com/Seldaek/monolog into CMS Made Simple
Post install, Monolog must be installed using Composer. Two choices:
cd modules/CMSMonolog composer update
composer require monolog/monolog
require_once __DIR__."/vendor/autoload.php";
After installation, logs are viewed in Site Admin -> CMS Monolog.
Logging is provided via the MLog static functions (levels are defined per Monolog)
| Level |
Method |
Parameters |
|---|---|---|
| Debug | MLog::d | (channel, debug message, variable1, variable2, ...); |
| Info | MLog::i | (channel, debug message, variable1, variable2, ...); |
| Warning | MLog::w | (channel, debug message, variable1, variable2, ...); |
| Error | MLog::e | (channel, debug message, variable1, variable2, ...); |
| Critical | MLog::c | (channel, debug message, variable1, variable2, ...); |
| Alert | MLog::a | (channel, debug message, variable1, variable2, ...); |
Example:
MLog::d(__METHOD__, "Starting process, parameters: ", $params);
If "Email on Error" is selected in settings (and your email is specified), then Error, Critical and Alert levels generate emails.
None
This software is provided as-is. Please read the text of the license for the full disclaimer.
Copyright © 2015, Mike Crowe<EMAIL_ADDRESS>All Rights Are Reserved.
Monolog is licensed under the MIT License - see the `LICENSE` file for details. You must agree to this license before using the module.


Computer Science Department, Technion - Israel Institute of Technology, Haifa, Israel |
For the following scenario:
map:rel_paper_topic1 a d2rq:PropertyBridge; d2rq:belongsToClassMap map:Papers; d2rq:property skos:primarySubject; d2rq:property skos:subject; d2rq:refersToClassMap map:Topics; d2rq:condition "rel_paper_topic.RelationType = 1"; d2rq:join "rel_paper_topic.PaperID = papers.PaperID"; d2rq:join "rel_paper_topic.TopicID = topics.TopicID"; . map:rel_paper_topic2 a d2rq:PropertyBridge; d2rq:belongsToClassMap map:Papers; d2rq:property skos:subject; d2rq:refersToClassMap map:Topics; d2rq:condition "rel_paper_topic.RelationType = 2"; d2rq:join "rel_paper_topic.PaperID = papers.PaperID"; d2rq:join "rel_paper_topic.TopicID = topics.TopicID"; .When a new triple with a property skos:subject is inserted, which RelationType should be written, '1' or '2'?


_Double_Jeopardy_ (R) ** (out of ****)
_Double_Jeopardy_ boasts a hook that is killer--literally. A woman is framed her husband's murder and is accordingly sentenced to prison. While in the pen, she discovers that her husband is, in fact, alive and kicking. Informed of the "double jeopardy" law--that is, that no person can be tried for the exact same crime twice--she decides to serve her time and, once she's released, _really_ off her not-so-dear hubby. After all, no officer of the law can touch her for committing a crime she has already "committed," no?
The few times I saw the trailer for _Double_Jeopardy_, the clip where the woman in question, Libby Parsons (Ashley Judd), is told about double jeopardy by a fellow inmate (Roma Maffia), was greeted with hearty applause. And during my screening of the film, that same scene, in its complete form, was met with the same approval. But that's just five minutes in a film that lasts at least 100, and in time it becomes clear that the hook is all there is to _Double_Jeopardy_, with nothing equally as interesting or surprising left to fill in the blanks.
The presence of Judd in the lead does go a long way in keeping the film watchable. Libby breaks her parole in Washington state and tracks down her deceitful husband Nick (Bruce Greenwood) all the way down to New Orleans, Judd is never less than believable, and as such there is little difficulty buying into the often-preposterous proceedings. Also contributing to the urgency is Tommy Lee Jones, whose strongly _Fugitive_-esque role as parole officer Travis Lehman is indeed one he can play in his sleep, but that doesn't mean that he's any less entertaining.
With the actors doing the best they can, the blame for this less-than-thrilling thriller falls on director Bruce Beresford and writers David Weisberg and Douglas S. Cook. From the premise, it's quite obvious how the film's going to end.  (And if the film didn't end that way, a test screening would have surely changed that.) So it's up to the filmmakers to flesh out the whole, and all they come up with is the idea of lost children. In an obvious effort to keep Libby from being too coldblooded, her main motive to find her husband is not to even the score, but to see her son again; to add some sort of bonding point between her and Lehman, he's saddled with an arbitrary back story where his own daughter was taken away from him after a DUI infraction. The more action-oriented "suspense" points that come along the way aren't much more effective. One too many scenes has Libby smash up a car, and one critical scene down the stretch has the villain committing the mistake made by _Austin_Powers_' Dr. Evil--that is, assuming the heroine is left for dead when it would be much easier to make quick work of her.
But most people won't think of these things while watching _Double_Jeopardy_, and the film may end up sufficiently entertaining audiences. However, it must be said that while there was some clapping at the end of the film, the applause was nothing compared to that which greeted the "double jeopardy" scene. It just goes to show that while a great hook does count for something, it takes a lot more to reel an audience in.
Michael Dequina<EMAIL_ADDRESS>|<EMAIL_ADDRESS>|<EMAIL_ADDRESS>|<EMAIL_ADDRESS>Mr. Brown's Movie Site: http://welcome.to/mrbrown CompuServe Hollywood Hotline: http://www.HollywoodHotline.com on ICQ: #25289934 | on AOL Instant Messenger: MrBrown23
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


No Comment
Remove comment sections from various sites.
Install uBlock Origin
Subscribe to the No Comment filter list
No Comment on GitHub


{% extends 'layouts/layout.html' %} {% block pageTitle %} This link does not work {% endblock %} {% block content %}
This could be because:
You can try again by following the link in the email.


WELCOME TO OUR WORLD
Short Description
For centuries people have waged war. Many wars took away many good people. Fathers left families, husbands left loved ones, the color of the nation perished. But not now. We offer you upscale troops. Each soldier is trained personally under you, only today discounts up to 50%!
Skills
Every unit must prove to be a professional. Therefore, everyone learns not only the art of war as its standard
OUR TROOPS
Emperors! Choose the troops you will go with to battle with whom you will reach your glory!
GREEKS HOPLITES
We went with Macedonian to India. We were the first to conquer the seas. We are citizens and warriors of our poles, we will not back down, but let us help in the battle of smiling death.
CARTHAGE WARIORS
We were once driven from our lands Once we did not have a home, and when we found it, we had to protect it Now, we are the most powerful in the whole Mediterranean sea We will fight for our home, we will fight for our freedom
WHAT THEY SAY
CONTACT ME
Please contact me, if need more information about troops, or need one


How the Antarctic Circumpolar Current helps keep Antarctica frozen
The Antarctic Circumpolar Current, or ACC, is the strongest ocean current on our planet. It extends from the sea surface to the bottom of the ocean, and encircles Antarctica.
It is vital for Earth's health because it keeps Antarctica cool and frozen. It is also changing as the world's climate warms. Scientists like us are studying the current to find out how it might affect the future of Antarctica's ice sheets, and the world's sea levels.
The ACC carries an estimated 165 million to 182 million cubic metres of water every second (a unit also called a "Sverdrup") from west to east, more than 100 times the flow of all the rivers on Earth. It provides the main connection between the Indian, Pacific and Atlantic Oceans.
The tightest geographical constriction through which the current flows is Drake Passage, where only 800 km separates South America from Antarctica. While elsewhere the ACC appears to have a broad domain, it must also navigate steep undersea mountains that constrain its path and steer it north and south across the Southern Ocean.
What is the Antarctic Circumpolar Current?
A satellite view over Antarctica reveals a frozen continent surrounded by icy waters. Moving northward, away from Antarctica, the water temperatures rise slowly at first and then rapidly across a sharp gradient. It is the ACC that maintains this boundary.
The ACC is created by the combined effects of strong westerly winds across the Southern Ocean, and the big change in surface temperatures between the Equator and the poles.
Ocean density increases as water gets colder and as it gets more salty. The warm, salty surface waters of the subtropics are much lighter than the cold, fresher waters close to Antarctica. We can imagine that the depth of constant density levels slopes up towards Antarctica.
The westerly winds make this slope steeper, and the ACC rides eastward along it, faster where the slope is steeper, and weaker where it's flatter.
Fronts and bottom water
In the ACC there are sharp changes in water density known as fronts. The Subantarctic Front to the north and Polar Front further south are the two main fronts of the ACC (the black lines in the images). Both are known to split into two or three branches in some parts of the Southern Ocean, and merge together in other parts.
Scientists can figure out the density and speed of the current by measuring the ocean's height, using altimeters. For instance, denser waters sit lower and lighter waters stand taller, and differences between the height of the sea surface give the speed of the current.
The path of the ACC is a meandering one, because of the steering effect of the sea floor, and also because of instabilities in the current.
The ACC also plays a part in the meridional (or global) overturning circulation, which brings deep waters formed in the North Atlantic southward into the Southern Ocean. Once there it becomes known as Circumpolar Deep Water, and is carried around Antarctica by the ACC. It slowly rises toward the surface south of the Polar Front.
Once it surfaces, some of the water flows northward again and sinks north of the Subarctic Front. The remaining part flows toward Antarctica where it is transformed into the densest water in the ocean, sinking to the sea floor and flowing northward in the abyss as Antarctic Bottom Water. These pathways are the main way that the oceans absorb heat and carbon dioxide and sequester it in the deep ocean.
Changing current
The ACC is not immune to climate change. The Southern Ocean has warmed and freshened in the upper 2,000 m. Rapid warming and freshening has also been found in the Antarctic Bottom Water, the deepest layer of the ocean.
Waters south of the Polar Front are becoming fresher due to increased rainfall there, and waters to the north of the Polar Front are becoming saltier due to increased evaporation. These changes are caused by human activity, primarily through adding greenhouse gases to the atmosphere, and depletion of the ozone layer. The ozone hole is now recovering but greenhouse gases continue to rise globally.
Winds have strengthened by about 40% over the Southern Ocean over the past 40 years. Surprisingly, this has not translated into an increase in the strength of the ACC. Instead there has been an increase in eddies that move heat towards the pole, particularly in hotspots such as Drake Passage, Kerguelen Plateau, and between Tasmania and New Zealand.
We have observed much change already. The question now is how this increased transfer of heat across the ACC will impact the stability of the Antarctic ice sheet, and consequently the rate of global sea-level rise.
Explore further
This article is republished from The Conversation under a Creative Commons license. Read the original article.
User comments
Please sign in to add a comment. Registration is free, and takes less than a minute. Read more


Hi! I'm Waffles, Tetazoo's cat. You can check in on what I'm up to here!
Waffles' most recent Zephyr :
"{z}"
Contact<EMAIL_ADDRESS>Special thanks to cela (for web help), lnor (for moral support), ProjX (for money), rdedhia (for name), and MITERS (for roomba)


|
Dear UNSW Computer Science &
Engineering Students,
You are
invited to:
Sponsor:
www.ssw.com.au
Presenter:
Adam Cogan
–
Chief Architect, B.Bus, JP, MCP, MVP
Adam is one of only three
Microsoft Regional Directors in Australia. In this role, he regularly presents in conferences such as
TechEd (USA, Australia, New Zealand and Malaysia) and .NET user group around the
world. He has been the Microsoft MVP (Visual Studio Team System) since 2005. In
addition, He has received Bronze medal of Microsoft Regional Director Program
Global Impact Award in 2007.
When:
Wednesday
2nd
April 2008.
Time:
12-2pm
Where:
UNSW
Building K17 Level 1 Seminar Room.
Map
http://www.cse.unsw.edu.au/about-us/
Lunch:
Food
& drinks provided
Confirmation:
Please confirm your interest by email to
Email Helen for ease of
ordering lunch for all attendees.
Presentation Topics
1.
What Microsoft Technology can ofWhat Microsoft Technology can offer you in your
future career
2.mes New Roman"">
Java VS .NET
3.
Sharpen your sword with C# and .NET 3.5
4.
Why is Windows Server 2008 important
5.
Powerful tools – Visual Studio 2008
6.
Powerful teams - Team Foundation Server
7.
Powerful collaboration - SharePoint
8.
Light up the Web – Silverlight
9.
What’s next – getting a job
About SSW
We are a specialist IT Consulting Company based in Neutral Bay, Sydney. We have
had 16 years of experience implementing best of breed solutions that improve
your operating efficiency and competitive advantage. We deliver scalable and
extensible custom solutions on top of the latest Microsoft technologies. Our
consultants are Microsoft Certified Professionals, continually trained in Best
Practices. We have been servicing: Sydney NSW, Melbourne VIC, Brisbane QLD,
Canberra ACT and Adelaide SA. Cities we have representatives in: Los Angeles
(CA, US), Portland (OR, US), and San Francisco (CA, US).
What We Do
�
Web Development
�
Content Management System
�
Windows and Rich Client Development
�
Microsoft .NET Development
�
Integrated Business Systems
�
Mobile Application Development
�
Business Intelligence
�
Windows Vista Deployment
Our Rules &
Standards
Secret ingredients to quality software.
Whenever you are doing something more than once there should be a standard.
SSW standards
manage our coding, development, project management, email and phone
communication. However, we don't follow them blindly. If someone suggests a
better way of doing something, then we change the standard.
Sydney .NET User Group
The best place
to learn .NET for free in Sydney
Learn. Build
contacts. Socialise.
Every month, SSW hosts the Sydney .NET User Group where developers meet to
exchange ideas and listen to presentations by local and international industry
experts. Topics focus on .NET development, with a splattering of SQL, SharePoint
and Access. We also love discussing the latest industry news and exciting new
trends.
|


Back to Github/README.md
By clicking 'Accept' on page load, you have registered this page with your browser, and now it can act as a test wallet.
You can now test the Credential Handler API by requesting to be issued a credential, below.
This is a minimal credential Issuer application that demonstrates how a user would ask for a credential to be issued (using CHAPI's store() under the hood).
store()
When you click the Receive button, a Verifiable Credential will be issued and sent to your digital wallet for storage.
This is the Credential that gets issued (wrapped in a VerifiablePresentation by the issuer), and will be sent to the wallet:


{{#contentFor "title"}}Grid{{/contentFor}} {{#contentFor "tabName"}}grid{{/contentFor}} {{!< layouts/components.html}}
Our frontend system is based on Bootstrap 3, which includes several components and options for laying out your pages. You can create a basic grid system that starts out stacked on mobile devices and tablet devices (the extra small to small range) before becoming horizontal on desktop (medium) devices.
Containers are the most basic layout element in Bootstrap and are required when using our grid system. In most cases, you'll want to use a .container-fluid
for a full width container, spanning the entire width of the viewport.
For proper alignment and padding, .row
must be placed within either a .container
or .container-fluid
. Columns should be immediate children of rows, and only columns should contain content.
Columns use an equal amount of space in the parent container. This automatic sizing allows you to achieve most desired outcomes. Our system is composed of 12 flexible columns with a 40px gutter (20px on the left and right of each column).
You can specify columns to span across the 1-12 columns.

We use the following media queries in our Less files to create the key breakpoints in our grid system.
/* Small devices (tablets, 768px and up) */
@media (min-width: @screen-sm-min) { ... }
/* Medium devices (desktops, 992px and up) */
@media (min-width: @screen-md-min) { ... }
/* Large devices (large desktops, 1200px and up) */
@media (min-width: @screen-lg-min) { ... }
/* Extra Large devices (wide screen desktops, 1800px and up) */
@media (min-width: @screen-xl-min) { ... }
Using a single set of .col-md-*
grid classes, you can create a basic grid system that starts out stacked on mobile devices and tablet devices (the extra small to small range) before becoming horizontal on desktop (medium) devices. Place grid columns in any .row
.

.col-md-4

.col-md-8

.col-md-4

.col-md-4

.col-md-4

.col-md-6

.col-md-6

Move columns to the right using .col-md-offset-*
classes. The left margin of a column will be increased by *
columns.

.col-md-4

.col-md-4 .col-md-offset-4

.col-md-3 .col-md-offset-3

.col-md-3 .col-md-offset-3

Change the order of grid columns with .col-md-push-*
and .col-md-pull-*
modifier classes. For example, stacked content on mobile can be reordered horizontally on desktop (medium) devices.

.col-md-9 .col-md-push-3

.col-md-3 .col-md-pull-9


runtime.heapStatsDelta.released (field)
10 uses
runtime (current package)
metrics.go#L159: out.scalar = uint64(in.heapStats.released)
metrics.go#L236: out.scalar = uint64(in.heapStats.committed+in.heapStats.released) +
mgcscavenge.go#L738: atomic.Xaddint64(&stats.released, nbytes)
mheap.go#L1285: atomic.Xaddint64(&stats.released, -int64(scav))
mheap.go#L1377: atomic.Xaddint64(&stats.released, int64(asize))
mstats.go#L691: if memstats.heap_released != uint64(consStats.released) {
mstats.go#L693: print("runtime: consistent value=", consStats.released, "\n")
mstats.go#L769: released int64 // byte delta of released memory generated
mstats.go#L791: a.released += b.released
The pages are generated with Golds v0.2.7-preview. (GOOS=darwin GOARCH=amd64)


New features
Mesontest
Mesontest is a new testing tool that allows you to run your tests in many different ways. As an example you can run tests multiple times:
mesontest --repeat=1000 a_test
or with an arbitrary wrapper executable:
mesontest --wrap='valgrind --tool=helgrind' a_test
or under gdb, 1000 times in a row. This is handy for tests that fail spuriously, as when the crash happens you are given the full GDB command line:
mesontest --repeat=1000 --gdb a_test
Mesonrewriter
Mesonrewrite is an experimental tool to manipulate your build definitions programmatically. It is not installed by default yet but those interested can run it from the source repository.
As an example, here is how you would add a source file to a build target:
mesonrewriter add --target=program --filename=new_source.c
Shared modules
The new shared_module
function allows the creation of shared modules, that is, extension modules such as plugins that are meant to be used solely with dlopen
rather than linking them to targets.
Gnome module
- Detect required programs and print useful errors if missing
gtkdoc
- Allow passing a list of directories to
src_dir
kwarg - Add
namespace
kwarg - Add
mode
kwarg - Fix
gtkdoc-scangobj
finding local libraries
compile_resources
- Add
gresource_bundle
kwarg to output.gresource
files - Add
export
andinstall_header
kwargs - Use depfile support available in GLib >= 2.52.0
i18n module
- Add
merge_file()
function for creating translated files - Add
preset
kwarg to included common gettext flags - Read languages from
LINGUAS
file
LLVM IR compilation
Meson has long had support for compiling assembler (GAS) files. In this release we add support for compiling LLVM IR files in a similar way when building with the Clang compiler. Just add it to the list of files when creating a library
or executable
target like any other source file. No special handling is required:
executable('some-exe', 'main.c', 'asm-file.S', 'ir-file.ll')
As always, you can also mix LLVM IR files with C++, C, and Assembly (GAS) sources.
ViM indent and syntax files
We now include filetype, indent, and syntax files for ViM with the source tree. Please file issues (or pull requests!) for enhancements or if you face any problems using them.
Push URLs in .wrap files
.wrap files for subprojects can now include a separate push URL to allow developers to push changes directly from a subproject git checkout.
pkg-config dependencies
Meson now supports multiple version restrictions while searching for pkg-config dependencies.
# Just want a lower limit
dependency('zlib', version : '>1.2.1')
# Want both a lower and an upper limit
dependency('opencv', version : ['>=2.3.0', '<=3.1.0'])
# Want to exclude one specific broken version
dependency('foolite', version : ['>=3.12.1', '!=3.13.99'])
Overriding more binaries with environment variables
You can now specify the binary to be used for the following tools by setting the corresponding environment variable
| Name | Environment variable |
|---|---|
| pkg-config | PKG_CONFIG |
| readelf | READELF |
| nm | NM |
Support for localstatedir
Similar to other options such as bindir
and datadir
, you can now specify the localstatedir
for a project by passing --localstatedir=dir
to meson
or -Dlocalstatedir=dir
to mesonconf
after configuration. You can also access it from inside the meson.build
file with get_option('localstatedir')
.
New compiler function symbols_have_underscore_prefix
Checks if the compiler prefixes an underscore to C global symbols with the default calling convention. This is useful when linking to compiled assembly code, or other code that does not have its C symbol mangling handled transparently by the compiler.
cc = meson.get_compiler('c')
conf = configuration_data()
if cc.symbols_have_underscore_prefix()
conf.set('SYMBOLS_HAVE_UNDERSCORE', true)
endif
C symbol mangling is platform and architecture dependent, and a helper function is needed to detect it. Eg: Windows 32-bit prefixes underscore, but 64-bit does not. Linux does not prefix an underscore but OS X does.
Vala
Glib Resources compiled with gnome.compile_resources
that are added to the sources of a Vala build target will now cause the appropriate --gresources
flag to be passed to the Vala compiler so you don't need to add that yourself to vala_args:
.
Improvements to install scripts
You can now pass arguments to install scripts added with meson.add_install_script()
. All arguments after the script name will be passed to the script.
The MESON_INSTALL_DESTDIR_PREFIX
environment variable is now set when install scripts are called. This contains the values of the DESTDIR
environment variable and the prefix
option passed to Meson joined together. This is useful because both those are usually absolute paths, and joining absolute paths in a cross-platform way is tricky. os.path.join
in Python will discard all previous path segments when it encounters an absolute path, and simply concatenating them will not work on Windows where absolute paths begin with the drive letter.
More install directories
Added new options sbindir
and infodir
that can be used for installation.
The results of the search are


A Java library to ease the life of web developers by providing automatic logging of input, output and some context data for controllers.
> INFO:
getUser()
called via url
[http://localhost:8080/get-random-user],
username [username]
> INFO:
getUser()
took
[1.8 ms]
to complete
> INFO:
getUser()
returned:
[User(id=SP-937-215,
<EMAIL_ADDRESS>password=xxxxx,
firstName=Jean-Luc,
lastName=Picard)]
> INFO:
getMemo()
called via url
[http://localhost:8080/get-memo],
username [username]
> INFO:
getMemo()
took
[0.2 ms]
to complete
> INFO:
getMemo()
returned:
[Memo(id=m_xyz_123, text=Hello, World! From a Memo!)]
Create a bean, add an annotation to your class and you're ready to rock! It takes just six lines total to add it to a project!
Precisely control what gets logged and what doesn't. Use provided annotations to achieve fine-grain control over logging. More customizations to follow soon.
Prevent sensitive data such as passwords, api keys from being logged via data scrubbing. Easily extend items to be scrubbed for customized security.
While working on a project, a Spring-based web application, it quickly became annoying adding the same log statements for each new controller method being created. Working in a team made it inconsistent too with people forgetting or adding unformatted logs. This was the perfect use case for AOP (Aspect Oriented Programming). This library is re-built based on experience gained during my original implementation of AOP based logging.
No more imcomplete logs. No more inconsistent logs. Always be ready with complete information for debugging or tracing down errors.
Read moreWhat could be more simpler?
// add project dependency compile 'io.github.harshilsharma63:controller-logger:1.2.3'
// create a bean for AOP weaver to pick @Bean public GenericControllerAspect genericControllerAspect() { return new GenericControllerAspect(); }
// add this annotation to your controller classs @Logging
We make no compromises with your security
With a data scrubbing feature (enabled by default) built in, you don't need to worry about sensitive information getting logged. It scrubs information such as passwords, auth tokens, API keys and you can extend it as well to match your custom requirements.
> INFO:
getResource() called with arguments apiKey: [xxxxx]
called via url
[http://localhost:8080/get-resource],
username [username]
Use provided annotations to fine-grain your logging setup
Using the @Logging
and @NoLogging
annotations, target exactly the classes and methods you want logging to work for or to skipped.
@RestController @Logging public class UserController { // everything here will be logged // due to @Logging annotation on class ... @NoLogging @RequestMapping("/is-active") @RequestBody public bool isActive(@RequestParam String userId) { // expect this // this won't be logged due to @NoLogging on this method } }
Your business logic stays unaffected
Your business logic stays unaffected by any error that may occur (just saying!) in the logging logic. Your code gets executed everytime, as if you never had this library!
// the code is on similar lines... try { // all the logging logic... } catch (Exception e) { // catches anything that goes wrong. Doesn't really happen though :D } result = proceedingJoinPoint.proceed(); // your business logic is execited here try { // post execution logging logic ... } catch (Exception e) { // catch everything }
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Obcaecati vel exercitationem eveniet vero maxime ratione
Read moreAvailable on Maven Central, or can be downloaded manually from GitHub
*Works on Java 8 and Spring Boot 1.5
Gurgaon, India


WebSockets Demo
your IP address:
Uptime :
IFace :
RX bytes :
TX bytes :
Set update frequency
(seconds)
⬆
⬇
0 disables updates


When I was younger I had ADD/HD really bad. I couldn't focus on anything and I bounced off the walls. It felt like a million things were going through my mind and I had no control over them. I did very poorly in school and generally got into trouble/fights because everything I did was a total knee-jerk reaction.
 So my parents did. For five years I took varying forms of Ritalin. It was horrible. Sure I calmed down and stopped talking but I didn't have control. It cured the hyperactivity and to a lesser extent the attention problems but Ritalin wanted to slow everything down. Essentially it made me walk when i wanted to run.
So fast forward some years. I took Ritalin off and on in highschool just to get by for exams, usually the end of the year. Then came college and I did okay, having sort of grown out of the add/hd phase. Then a friend told me about Adderall. He said it would put me in absolute control of whatever I wanted to do. I could focus on something to near exhaustion. Now having played tournament chess and working with computers most of my life I thought this was grand. So I asked my doctor and he gave me some 5mg to start with. Now for me, 6'1, 200lbs, 5mg was nothing. So after three days I took a higher dosage: 15mg. That worked but only for an hour or two. I literally just fell asleep two hours after taking it. So I took 20mg and finished out the Rx with that; three days.
The 20mg worked great. I could sit down and take notes like mad, read anything, study for 8hrs straight. After about four months of this it began to feel like I only had a five hour window of positive effect. The remainder of the day was like drinking lots of coffee/soda. The true effects of Adderall were gone.
So I asked and I was given 30mg. I am on day six of 30mg and its very strange. I am obsessively interested in anything and everything. It doesn't matter what it is, if my mind finds it itneresting, I'm diving head first into it for hours. However at the same time I become a very quiet, intense person. No smile. NO personality. Intensity. Everything is to-the-wall. I sit and study for 10hrs at a time. I take it at 8am and then even at 11pm I am sitting in the bed twitching. Soemthing has to be moving. When I am just sittign at a desk writing (like now) my leg is shaking, bouncing. It's like my mind is using what it needs to stay on top of the world and whatever else has to get out some way else.
Basically this drug is a horrible but amazing thing. The reason I say this is because if you can take the side effects of the twitchiness (your hands and legs mostly just want to kind of move or shake), decreased libido (not really decreased but it takes much longer to reach orgasm), biting of the inner linning of the mouth; not grinding but its like one set of teeth just once to press against the other set just to make sure they're there; weight loss/appetitie supression: with 30mg my mind has forgotten I need to eat. I actually have to set a reminder alarm to eat now. I feel hunger pains and stomach growling but I don't conciously think 'thats because I need to eat' but rather 'my stomach is just making noise and hurts'.
All in all I will continue taking it. It helps me focus and study and I feel more confident, lucid, and in command. I don't feel euphoric or like a God. It's as though I have complete control over my mind. I do what I want to do and I do it until I decide to stop; exhaustion is nothing.
The only complaint is I have to personality and I always feel like Im in a very intense, focused situation. If you are going to take Adderall you need to get up and take it early in the morning and then set a time to 'wind down'. If your normal bed time is 11pm, make it 9pm instead. Sleep requires an extra hour or so to get into.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


Adding a URL Link
How to insert a link to a URL located on another web site using the DotNetNuke.RadEditorProvider for the RTE.
- Highlight the text/object for the link - OR - Place you cursor where you want to insert the link.
- Click the Hyperlink Manager (CTRL + K) button. This opens the Hyperlink Manager with the Hyperlink tab pre-selected.
- In the URL text box, enter the URL address for this link.
- Optional. In the Link Text text box, enter the text for this link. If you highlighted text at Step 1, then this field will be pre-populated with that text. Note: This field is not displayed when adding a link to an image.
- Optional. At Target, select the target window for this link.
- Optional. In the Tooltip text box, enter a tool tip to be displayed when a user places their mouse over this link.
- Optional. At CSS Class, select a class for the link - OR - Select Clear Class to use the default class.
-
Click the OK button confirm.


This week Cypress donated 21 high-end MacBook Pro laptops to Refcode. The laptops will be loaned to students taking the Intro to Professional Software Engineering course and those who graduate will get to keep the laptop for free!
Refcode founder and director Brenton Strine made a video to commemorate the donation. "This silly '21 gun salute' video may seem overly dramatic, but it's really not, when you consider the impact it has for the Refcode program, and on the 21 refugees and immigrants who will take them home" he said.
By donating these laptops, Cypress is helping provide the opportunity for America's newest patriots to live the American dream and create a better future for themselves and their families. Many refugees and immigrants have the talent, time, and aptitude to learn compputer programming, but are limited by their financial situations and access to a computer. Providing a high-end MacBook Pro to each student, we're giving them the best possible chance to succeed as they persue a challenging path of learning, coding, programming, and gaining the experience needed in an incredibly competitive job market.
"Wow, these are really, really nice" said Malek Alarmash, the Refcode Program Manager when he saw them. "I'm actually kinda jealous, can I take one for myself?" said Luke Keller, the Executive Director of Tekton.
Cypress employees Grant and Reggie dropped off the laptops and helped the Refcode Program Manager Malek get them processed. The laptops had a range of specifications, but were mostly high end, e.g. a 2019 MacBook Pro with Touchbar, an 8 core i9 processor and 32GB of RAM.
The laptops had been used by Cypress employees and had been handed off to the facilities department to decomission and dispose of. Cypress does not re-issue laptops to employees after they've been used, so facilities must find a way to responsibly sell or dispose of them. Not only did donating them save time and expense of that effort, but they went to a really good cause.
If your company issues laptops and you think they may be willing to donate decomissioned units to Refcode, please get in touch with us!


Ava Grantham
I did it!
Here are my pages
Run After It
A choose your way story about a kitten.
The Ava Challenge
Take a hard/fun quiz to show how much you know about Ava.
The Fight
A comic about a wizard.


He weight: {{person.weight}} kg
He height: {{person.height}} cm
Name is required!
Weight is required!
Height is required!


Click on any of the demos below to get an idea of the types of things you can do with abcjs. If this is your first time using abcjs, the demos in the first section are suggested as they are the easiest to set up. After loading each demo, right-click the webpage and choose "view page source" to see how the demo works.
| Start Here | |
| Basic | A demo of the most bare-boned way to display sheet music. |
|---|---|
| Editor | A demo of the simplest way to present the user with an editor so they can change music on the fly. |
| Basic Synth | A demo of the most basic way to incorporate audio playback using abcjs. |
| Analysis | A demo of the information that is available about an ABC tune book. |
| Visual Demos | |
| Animation | A demo of animated cursor effects that can be added using abcjs. |
| Annotating | A demo showing how to annotate your sheet music using abcjs. |
| Basic | A demo of the most bare-boned way to display sheet music. |
| Change Glyphs | A demo showing how to substitute the music symbols with your own. |
| Line Wrapping | A demo of the line wrapping capabilities. |
| Plugin | A demo showing how to use the plugin version of abcjs. (Useful for sites with a CMS where a user might enter ABC code) |
| Printable | A demo showing how to format the music for printing. |
| Responsive | A demo showing the music filling up whatever available horizontal space is on the page. |
| Zoom To Fit | A demo showing the music filling up whatever available space is on the page. |
| Transpose | A demo showing how to transpose. |
| Output Transposed ABC | A demo showing how to transpose and output the result of the transposition. |
| Tablature | A demo showing how to create tablature. |
| Tune Book | A demo showing how to pick tunes from a tune book. |
| Automatically Add Note Names | A demo of modifying the SVG output after drawing to add note names. |
| Interactive Demos | |
| Dragging | A demo showing how to implement a visual interface that supports dragging. |
| Editor | A demo of the simplest way to present the user with an editor so they can change music on the fly. |
| Editor With Synth | A demo of the editor with synth capabilities |
| Editor With Transpose | A demo of the editor and transposing |
| Audio Demos | |
| Basic Synth | A demo of the most basic way to incorporate audio playback using abcjs. |
| Karaoke | A demo of allowing the user to turn off voices. |
| Microtones | A demo of creating non-western music that relies on a different scale. |
| Modify Synth Input | A demo showing how to tweak the synth after the music has been processed. |
| Play On Repeat | A demo showing how to loop a section of the music. |
| Synth Only | A demo showing how to create sound without any visual representation. |
| Synth Options | A full-featured demo with many synth options. |
| Synth Player | A demo showing how to use abcjs' synth player. |
| Tempo Changing | Showing how to control the tempo. |
| Tune/Instrument Switcher | Showing how to render and switch multiple tunes and change instruments. |
| Analysis | |
| Analysis | A demo of the information that is available about an ABC tune book. |
| Parsing | A demo of getting lyrics out of an abc string. |


Lorem Ipsum is simply dummy text of the printing and typetook a galley of type and scrambled it to make a type d not only fiveLorem Ipsum is simply dummy text of the printing and typetook a galley of type and scrambled it to make a type specimen book. It has survived not only


Subscribe
A bi-weekly digest of all things Devops, FOSS and sometimes life.
This newsletter is beyond just a link aggregator. You should subscribe to this if you want to read my learnings from experimenting with Containers, Self hosting and developing software in general.


{%load static %}
Euro Travel
Toggle navigation
Flavours
Caterers And Events
Home
Login
services
contact
Top place to book Events
Book Beautiful Wedding Halls
Our Blazzing offers
Login To Book Amazing Offers
Affordable Pricing
Luxury Hotels
High class Vehicles
Highest Quality Food
Flavours Caterers And Events
Email Us
DONE


above |
Sun The Gentle, Wind |
|
below |
Sun The Gentle, Wind |
The Gentle. Success through what is small.
It furthers one to have somewhere to go.
It furthers one to see the great man.
Winds following one upon the other:
The image of the Gently Penetrating.
Thus the superior man
Spreads his commands abroad
And carries out his undertakings.
Six at the beginning means:
In advancing and in retreating,
The perseverance of a warrior furthers.
Nine in the second place means:
Penetration under the bed.
Priests and magicians are used in great number.
Good fortune. No blame.
Nine in the third place means:
Repeated penetration. Humiliation.
Six in the fourth place means:
Remorse vanishes.
During the hunt
Three kinds of game are caught.
Nine in the fifth place means:
Perseverance brings good fortune.
Remorse vanishes.
Nothing that does not further.
No beginning, but an end.
Before the change, three days.
After the change, three days.
Good fortune.
Nine at the top means:
Penetration under the bed.
He loses his property and his ax
Perseverance brings misfortune.


is it possible to create a plugin that adds the filter "LOCKED" to the Dog Tags page, besides to the existing filters All, Taken, Unlocked?
It's a little bit arduous to find Dog Tags you don't have unlocked yet, especially if you already have taken a lot of Dog Tags from enemies (placeholder Dog Tag is a little bit more obvious).
If it's too hard or not possible to write the plugin it's okay, it would be just a minor simplification.
Thanks in advance (for reading, creating, whatever)!