How to use _connect method in avocado

Best Python code snippet using avocado_python

dal.js

Source:dal.js Github

copy

Full Screen

...44 });45 }46 }47 async create (desc) {48 this._connect();49 const results = await this._run(`SELECT * FROM version LIMIT 1`, []);50 if (results.length > 0) {51 throw 'Version # already exists';52 }53 await this._run(`INSERT INTO version VALUES (?)`, [desc.version]);54 this._close();55 }56 async update (desc) {57 this._connect();58 const results = await this._run(`SELECT * FROM version LIMIT 1`);59 if (results.length > 0) {60 await this._run(`UPDATE version SET version = ?`, [desc.version]);61 }62 else {63 await this._run(`INSERT INTO version VALUES (?)`, [desc.version]);64 }65 this._close();66 }67 68 async read () {69 this._connect();70 const rows = await this._run(`SELECT * FROM version LIMIT 1`);71 if (rows.length > 0) { 72 return {version: rows[0].version}73 }74 }75}76class Tags {77 constructor (folder) {78 this._fname = path.join(folder, _IMAGES_DB);79 }80 _connect () {81 this._db = new sqlite3.Database(this._fname);82 }83 _close () {84 if (this._db) {85 this._db.close();86 }87 }88 _run (sql, params) {89 // allow queries to be using asynchronously90 if (this._db) { 91 return new Promise((resolve, reject) => {92 this._db.all(sql, params, function (error, rows) {93 if (error)94 reject(error);95 else96 resolve(rows);97 });98 });99 }100 }101 async create (desc) {102 this._connect();103 const rows = await this._run(`SELECT * FROM tags WHERE uuid = ? and tag = ? LIMIT 1`,104 [desc.uuid, desc.tag]);105 if (rows.length > 0) {106 throw `UUID ${desc.uuid} and tag ${desc.tag} already exist`;107 }108 await this._run(`INSERT INTO tags VALUES (?, ?)`, [desc.uuid, desc.tag]);109 this._close();110 }111 async delete (uuid, tag) {112 this._connect();113 await this._run(`DELETE FROM tags WHERE uuid = ? AND tag = ?`, [uuid, tag]);114 this._close();115 }116 async delete_all_by_uuid (uuid) {117 this._connect();118 await this._run(`DELETE FROM tags WHERE uuid = ?`, [uuid]);119 this._close();120 }121 async read_by_uuid (uuid) {122 this._connect();123 const rows = await this._run(`SELECT * FROM tags WHERE uuid = ?`, [uuid]);124 this._close();125 return rows;126 }127 async read_by_uuids (uuids) {128 this._connect();129 if (uuids.length > 990) {130 throw `About to hit the limit of the number of uuids that can be looked up at once`;131 }132 const uuid_str = uuids.map(r => '?').join(', ');133 const rows = await this._run(`SELECT * FROM tags WHERE uuid IN (${uuid_str})`, uuids);134 this._close();135 return rows;136 }137 async read_all_tags () {138 this._connect();139 let rows = await this._run(`SELECT distinct tag FROM tags`);140 // rows = rows.map(r => ({tag: r.tag}));141 this._close();142 return rows;143 }144}145class Images {146 147 constructor (folder) {148 this._fname = path.join(folder, _IMAGES_DB);149 }150 _connect () {151 this._db = new sqlite3.Database(this._fname);152 }153 _close () {154 if (this._db) {155 this._db.close();156 }157 }158 _run (sql, params) {159 // allow queries to be using asynchronously160 if (this._db) { 161 return new Promise((resolve, reject) => {162 this._db.all(sql, params, function (error, rows) {163 if (error)164 reject(error);165 else166 resolve(rows);167 });168 });169 }170 }171 async create (desc) {172 this._connect();173 const timestamp = toISO(new Date());174 let rows = await this._run(`SELECT * FROM images WHERE uuid = ? LIMIT 1`, [desc.uuid])175 if (rows.length > 0) {176 throw `UUID ${desc.uuid} already exists`;177 }178 await this._run(`INSERT INTO images VALUES (?, ?, ?, ?, ?, ?, ?)`, [179 desc.uuid,180 desc.extension,181 desc.content.join('\n\n'),182 timestamp,183 timestamp,184 null,185 desc.draft ? 1 : 0186 ]);187 this._close();188 }189 async update (desc) {190 this._connect();191 const timestamp = toISO(new Date());192 let rows = await this._run(`SELECT * FROM images WHERE uuid = ? LIMIT 1`, [desc.uuid]);193 if (rows.length > 0) {194 await this._run(`DELETE FROM images WHERE uuid = ?`, [desc.uuid]);195 }196 await this._run(`INSERT INTO images VALUES (?, ?, ?, ?, ?, ?, ?)`, [197 desc.uuid,198 desc.extension,199 desc.content.join('\n\n'),200 toISO(desc.date_created),201 timestamp,202 desc.date_published && desc.draft == 0 ? toISO(desc.date_published) : null,203 desc.draft ? 1 : 0204 ]);205 this._close();206 }207 async delete (uuid) {208 this._connect();209 await this._run(`DELETE FROM images WHERE uuid = ?`, [uuid]);210 this._close();211 }212 _process_row (r) {213 return { uuid: r.uuid,214 extension: r.extension,215 content: r.content.split('\n\n'),216 date_created: new Date(r.date_created),217 date_updated: new Date(r.date_updated),218 date_published: r.date_published ? new Date(r.date_published) : null,219 draft: r.draft ? true : false }220 }221 async count_all () {222 this._connect();223 const rows = await this._run(`SELECT count(*) as ct FROM images WHERE draft = 0`);224 this._close();225 return rows[0];226 }227 async count_all_drafts () {228 this._connect();229 const rows = await this._run(`SELECT count(*) as ct FROM images WHERE draft = 1 AND content IS NOT NULL AND content <> ''`);230 this._close();231 return rows[0];232 }233 async count_all_new () {234 this._connect();235 const rows = await this._run(`SELECT count(*) as ct FROM images WHERE draft = 1 AND (content IS NULL OR content = '')`);236 this._close();237 return rows[0];238 }239 async count_all_by_tag (tag) {240 this._connect();241 const rows = await this._run(`SELECT count(*) as ct FROM images WHERE uuid IN (SELECT uuid FROM tags WHERE tag = ?) AND draft = 0`, [tag]);242 this._close();243 return rows[0];244 }245 async read_all (offset, limit) {246 if (offset === 'undefined') {247 offset = 0;248 }249 if (limit === 'undefined') {250 limit = 10;251 }252 this._connect();253 let results = await this._run(`SELECT * FROM images WHERE draft = 0 ORDER BY datetime(date_published) desc LIMIT ? OFFSET ?`, [limit, offset]);254 results = results.map(r => this._process_row(r));255 this._close();256 return results;257 }258 async read_all_by_tag (tag, offset, limit) {259 if (offset === 'undefined') {260 offset = 0;261 }262 if (limit === 'undefined') {263 limit = 10;264 }265 this._connect();266 let results = await this._run(`SELECT * FROM images WHERE uuid IN (SELECT uuid FROM tags WHERE tag = ?) AND draft = 0 ORDER BY datetime(date_published) desc LIMIT ? OFFSET ?`, [tag, limit, offset]);267 results = results.map(r => this._process_row(r));268 this._close();269 return results;270 }271 async read_all_drafts (offset, limit) {272 if (offset === 'undefined') {273 offset = 0;274 }275 if (limit === 'undefined') {276 limit = 10;277 }278 this._connect();279 let results = await this._run(`SELECT * FROM images WHERE draft = 1 AND content IS NOT NULL AND content <> '' ORDER BY datetime(date_updated) desc LIMIT ? OFFSET ?`, [limit, offset]);280 results = results.map(r => this._process_row(r));281 this._close();282 return results;283 }284 async read_all_new (offset, limit) {285 if (offset === 'undefined') {286 offset = 0;287 }288 if (limit === 'undefined') {289 limit = 10;290 }291 this._connect();292 let results = await this._run(`SELECT * FROM images WHERE draft = 1 AND (content IS NULL OR content = '') ORDER BY datetime(date_updated) desc LIMIT ? OFFSET ?`, [limit, offset]);293 results = results.map(r => this._process_row(r));294 this._close();295 return results;296 }297 async read (uuid) {298 this._connect();299 const results = await this._run(`SELECT * FROM images WHERE uuid = ?` , [uuid]);300 if (results.length > 0) {301 if (results.length > 1) {302 throw `Too many rows ${results.length} for UUID ${uuid}`;303 }304 return this._process_row(results[0]);305 }306 }307}308class Notes {309 310 constructor (folder) {311 this._fname = path.join(folder, _IMAGES_DB);312 }313 _connect () {314 this._db = new sqlite3.Database(this._fname);315 }316 _close () {317 if (this._db) {318 this._db.close();319 }320 }321 _run (sql, params) {322 // allow queries to be using asynchronously323 if (this._db) { 324 return new Promise((resolve, reject) => {325 this._db.all(sql, params, function (error, rows) {326 if (error)327 reject(error);328 else329 resolve(rows);330 });331 });332 }333 }334 async create (desc) {335 this._connect();336 const timestamp = toISO(new Date());337 let rows = await this._run(`SELECT * FROM notes WHERE uuid = ? LIMIT 1`, [desc.uuid])338 if (rows.length > 0) {339 throw `UUID ${desc.uuid} already exists`;340 }341 await this._run(`INSERT INTO notes VALUES (?, ?, ?)`, [342 desc.uuid,343 desc.content.join('\n\n'),344 timestamp345 ]);346 this._close();347 }348 async update (desc) {349 this._connect();350 const timestamp = toISO(new Date());351 let rows = await this._run(`SELECT * FROM notes WHERE uuid = ? LIMIT 1`, [desc.uuid]);352 if (rows.length > 0) {353 await this._run(`UPDATE notes SET content = ?, date_updated = ? WHERE uuid = ?`,354 [desc.content.join('\n\n'), timestamp, desc.uuid])355 }356 else { 357 await this._run(`INSERT INTO notes VALUES (?, ?, ?)`, [358 desc.uuid,359 desc.content.join('\n\n'),360 timestamp361 ]);362 }363 this._close();364 }365 async delete (uuid) {366 this._connect();367 await this._run(`DELETE FROM notes WHERE uuid = ?`, [uuid]);368 this._close();369 }370 _process_row (r) {371 return {372 uuid: r.uuid,373 content: r.content.split('\n\n'),374 date_updated: new Date(r.date_updated)375 }376 }377 async count_all () {378 this._connect();379 const rows = await this._run(`SELECT count(*) as ct FROM notes`);380 this._close();381 return rows[0];382 }383 async read_all (offset, limit) {384 if (offset === 'undefined') {385 offset = 0;386 }387 if (limit === 'undefined') {388 limit = 10;389 }390 this._connect();391 let results = await this._run(`SELECT * FROM notes ORDER BY datetime(date_updated) desc LIMIT ? OFFSET ?`, [limit, offset]);392 results = results.map(r => this._process_row(r));393 this._close();394 return results;395 }396 async read (uuid) {397 this._connect();398 const results = await this._run(`SELECT * FROM notes WHERE uuid = ?` , [uuid]);399 if (results.length > 0) {400 if (results.length > 1) {401 throw `Too many rows ${results.length} for UUID ${uuid}`;402 }403 return this._process_row(results[0]);404 }405 }406}407module.exports = {408 Version: Version,409 Tags: Tags,410 Images: Images,411 Notes: Notes,...

Full Screen

Full Screen

mongoClient.js

Source:mongoClient.js Github

copy

Full Screen

1"use strict"2var {MongoClient,ObjectID} = require('mongodb');3var assert = require('assert');4var log4js = require('log4js');5var logger = log4js.getLogger();6class MongoDb {7 constructor(host, port, db, user, pw){8 return new Promise((done, fail) => {9 var auth = (user && pw) ? (user+':'+pw+'@') : '';10 port = port || 27017;11 MongoClient.connect(`mongodb://${auth}${host}:${port}/${db}`, (err, db) => {12 assert.equal(null, err);13 this._connect = db;14 done(this);15 })16 });17 }18 convQuery(query){19 try{20 if(query.hasOwnProperty('_id')){21 if(query['_id']['$in']){22 query['_id']['$in'] = query['_id']['$in'].map((tId) => ObjectID(tId));23 }else{24 query['_id'] = ObjectID(query['_id']);25 }26 }27 }catch(e){28 logger.error(e.message);29 }30 return query;31 }32 insert(collect, doc, options){33 return new Promise((done, fail) => {34 if(this._connect && doc){35 var coll = this._connect.collection(collect);36 coll[(Array.isArray(doc) ? 'insertMany' : 'insert')](doc, options, (err, info) => {37 err && logger.error(err)38 assert.equal(null, err);39 //logger.info(result);40 done(info);41 });42 }else{43 fail();44 }45 });46 }47 remove(collect, query, options){48 return new Promise((done, fail) => {49 if(this._connect && query){50 var coll = this._connect.collection(collect);51 var ret = coll.removeMany(query, options);52 // conver object id53 this.convQuery(query);54 55 done();56 }else{57 fail();58 }59 });60 }61 findAndModify(collect, query, doc, options){62 return new Promise((done, fail) => {63 if(this._connect && query && doc){64 var coll = this._connect.collection(collect);65 //this.convQuery(query);66 options = options || {};67 coll.findOneAndUpdate(query, doc, options).then((data) => {68 done(data);69 }).catch((e) => {70 fail(e);71 });72 }else{73 fail();74 }75 });76 }77 upSert(collect, query, doc, options){78 return new Promise((done, fail) => {79 if(this._connect && doc){80 var coll = this._connect.collection(collect);81 // conver object id82 this.convQuery(query);83 84 options = options || {};85 options.w = 1;86 options.upsert = true;87 88 coll[(Array.isArray(doc) ? 'updateMany' : 'update')](query, doc,options, (err, info) => {89 err && logger.error(err)90 assert.equal(null, err);91 done(info);92 });93 }else{94 fail();95 }96 })97 }98 query(collect, query, options){99 //logger.info('test')100 return new Promise((done, fail) => {101 if(this._connect){102 var coll = this._connect.collection(collect);103 // conver object id104 this.convQuery(query);105 106 //logger.info(coll);107 coll.find(query, options).toArray((err, info) => {108 assert.equal(null, err);109 done(info);110 });111 }else{112 fail();113 }114 });115 }116 buildIndex(collect, keys, reserve, extras){117 return new Promise((done, fail) => {118 if(this._connect){119 var coll = this._connect.collection(collect);120 var index = {};121 Array.isArray(keys) ? keys.map((key) => {index[key]= (reserve ? -1 : 1)}) : (index[keys]=(reserve ? -1 : 1));122 return callback ? coll.ensureIndex(index, extras, (err, indexName) => {123 assert.equal(null, err);124 console.log('buildIndex:'+indexName)125 done(indexName);126 }) : coll.ensureIndex(index, extras);127 }else{128 fail();129 }130 });131 }132 update(collect, query, doc){133 return new Promise((done, fail) => {134 if(this._connect){135 // conver object id136 this.convQuery(query);137 var coll = this._connect.collection(collect);138 return coll.updateOne(query, doc, {w:1}).then((info) => {139 done(info);140 }).catch((e) => {141 fail(e)142 });143 }else{144 fail();145 }146 });147 }148 checkIndex(collect, option){149 return new Promise((done, fail) => {150 if(this._connect){151 var coll = this._connect.collection(collect);152 return coll.indexInformation(option || {full:true}, (err, info) => {153 assert.equal(null, err);154 done(info);155 });156 }else{157 fail();158 }159 });160 }161}...

Full Screen

Full Screen

cardinfo.js

Source:cardinfo.js Github

copy

Full Screen

1 /******************************************************************************************************************* 2 Ä«µåÇҺΠ¾È³»3 *******************************************************************************************************************/4 $( document ).ready(function() {5 $('[cardinfo]').click(function(e) {6 $('#sp-cardinfo, #sp-cardinfo-loading').remove();7 var _url = $(this).data('url');8 var _offset = $(this).offset();9 var _load = '<div id="sp-cardinfo-loading" style="top:'+ (_offset.top-24) +'px;left:'+ (_offset.left-7) +'px;">ºÒ·¯¿À´ÂÁß</div>';10 var _now = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;11 $('body').prepend( _load );12 $('#sp-cardinfo-loading').fadeIn('fast');13 $.ajax({14 type: 'get',15 dataType: 'html',16 url: _url,17 success: function(data){18 var $result = $(data).filter('#sp-result').html();19 $('body').append( $result );20 $('#sp-cardinfo').css('height',$(document).height()).fadeIn('fast');21 //$('#sp-cardinfo > ul').css({'top':_offset.top,'left':_offset.left - 600});22 $('#sp-cardinfo > ul').css('top',_now + 100);23 $('#sp-cardinfo-loading').fadeOut();24 /* ¿¬µ¿ */25 var _connect;26 var _connectdata;27 if( $('#sp-cardinfo [connect="¹«ÀÌÀÚÇÒºÎ"]').size() ){28 $('#sp-cardinfo [connect="¹«ÀÌÀÚÇÒºÎ"]').each(function( a ){29 if( $(this).data('connect') ){30 _connectdata = $(this).data('connect').split('^');31 if( _connectdata.length == 1 ){32 _connect = '';33 _connect += '<ul>';34 _connect += ' <p>'+ _connectdata[0] +'</p>';35 _connect += '</ul>';36 $('#sp-cardinfo [connectbox="¹«ÀÌÀÚÇÒºÎ"]').append( _connect );37 }else if( _connectdata.length == 2 ){38 _connect = '';39 _connect += '<ul>';40 _connect += ' <li class="sp-title">'+ _connectdata[0] +'</li>';41 _connect += ' <li class="sp-content">'+ _connectdata[1] +'</li>';42 _connect += '</ul>';43 $('#sp-cardinfo [connectbox="¹«ÀÌÀÚÇÒºÎ"]').append( _connect );44 }45 }46 });47 }48 if( $('#sp-cardinfo [connect="ºÎºÐ¹«ÀÌÀÚÇÒºÎ"]').size() ){49 $('#sp-cardinfo [connect="ºÎºÐ¹«ÀÌÀÚÇÒºÎ"]').each(function( a ){50 if( $(this).data('connect') ){51 _connectdata = $(this).data('connect').split('^');52 if( _connectdata.length == 1 ){53 _connect = '';54 _connect += '<ul>';55 _connect += ' <p>'+ _connectdata[0] +'</p>';56 _connect += '</ul>';57 $('#sp-cardinfo [connectbox="ºÎºÐ¹«ÀÌÀÚÇÒºÎ"]').append( _connect );58 }else if( _connectdata.length == 2 ){59 _connect = '';60 _connect += '<ul>';61 _connect += ' <li class="sp-title">'+ _connectdata[0] +'</li>';62 _connect += ' <li class="sp-content">'+ _connectdata[1] +'</li>';63 _connect += '</ul>';64 $('#sp-cardinfo [connectbox="ºÎºÐ¹«ÀÌÀÚÇÒºÎ"]').append( _connect );65 }66 }67 });68 }69 },70 error: function(xhr,status,error){71 $('#sp-cardinfo-loading').html('Àá½Ã ÈÄ ´Ù½Ã ½ÃµµÇØÁÖ¼¼¿ä');72 setTimeout(function(){73 $('#sp-cardinfo-loading').fadeOut('fast');74 }, 2000);75 },76 timeout: 300077 });78 });79 //KEY EVENT80 $(document).keydown(function(e) {81 if (e.keyCode == 27) {82 $('#sp-cardinfo').fadeOut('fast');83 }84 });85 //$(document).on('click', '#sp-cardinfo, #sp-cardinfo > ul > button', function(e) {86 $('#sp-cardinfo, #sp-cardinfo > ul > button').live('click', function(){87 $('#sp-cardinfo').fadeOut('fast');88 });89 //$(document).on('click', ''#sp-cardinfo > ul', function(e) {90 $('#sp-cardinfo > ul').live('click', function(e){91 e.stopPropagation();92 });93 //$(document).on('click', '#sp-cardinfo > ul > p > button', function(e) {94 $('#sp-cardinfo > ul > p > button').live('click',function(){95 var _index = $('#sp-cardinfo > ul > p > button').index( $(this) );96 $('#sp-cardinfo > ul > p > button').removeClass('-on');97 $('#sp-cardinfo > ul > p > button').eq(_index).addClass('-on');98 $('#sp-cardinfo > ul > li').removeClass('-on');99 $('#sp-cardinfo > ul > li').eq(_index).addClass('-on');100 });...

Full Screen

Full Screen

service.test.js

Source:service.test.js Github

copy

Full Screen

1/*global bridge,assert,suite,setup,teardown,test*/2/*jshint esnext:true, maxlen:false*/3suite('Service /', function() {4 var service = bridge.service;5 setup(function() {6 this.sinon = sinon.sandbox.create();7 });8 teardown(function() {9 this.sinon.restore();10 });11 suite('Service#method()', function() {12 var fakeMessage;13 var myService;14 setup(function() {15 myService = service('service-name');16 fakeMessage = {17 type: '_method',18 foo: 'foo',19 data: {20 name: 'my-method',21 args: ['a', 'b', 'c']22 },23 event: { ports: [] },24 respond: sinon.spy()25 };26 });27 teardown(function() {28 myService.destroy();29 });30 test('it responds to the message with the return value', function() {31 myService.method('my-method', () => 'value');32 myService.emit('_method', fakeMessage);33 sinon.assert.calledWith(fakeMessage.respond, 'value');34 });35 test('it applys arguments to the callback', function() {36 var spy = sinon.spy();37 myService.method('my-method', spy);38 myService.emit('_method', fakeMessage);39 sinon.assert.calledWith(spy, 'a', 'b', 'c');40 });41 test('it throws if no method is found', function(done) {42 myService.method('my-method', () => {});43 fakeMessage.data.name = 'unknown';44 try { myService.emit('_method', fakeMessage); }45 catch (e) { done(); }46 });47 });48 suite('on connect', function() {49 var fakeMessage;50 setup(function() {51 fakeMessage = {52 type: '_connect',53 data: {54 clientId: 123,55 service: 'service1'56 },57 event: { ports: [] },58 setSourcePort: sinon.spy(),59 respond: sinon.spy()60 };61 });62 teardown(function() {});63 test('it does not respond if the service name does not match', function() {64 fakeMessage.data.service = 'service3';65 var myService = service('service1');66 myService.emit('_connect', fakeMessage);67 sinon.assert.notCalled(fakeMessage.respond);68 myService = service('service2');69 myService.emit('_connect', fakeMessage);70 sinon.assert.notCalled(fakeMessage.respond);71 myService = service('service3');72 myService.emit('_connect', fakeMessage);73 sinon.assert.called(fakeMessage.respond);74 });75 test('it does not respond if no clientId was provided', function() {76 delete fakeMessage.data.clientId;77 var myService = service('service1');78 myService.emit('_connect', fakeMessage);79 sinon.assert.notCalled(fakeMessage.respond);80 fakeMessage.data.clientId = 123;81 myService.emit('_connect', fakeMessage);82 sinon.assert.called(fakeMessage.respond);83 });84 test('it does not respond if the client is already connected', function() {85 var myService = service('service1');86 myService.emit('_connect', fakeMessage);87 sinon.assert.called(fakeMessage.respond);88 fakeMessage.respond.reset();89 myService.emit('_connect', fakeMessage);90 sinon.assert.notCalled(fakeMessage.respond);91 });92 test('it responds on MessageChannel the Client and Service are not within Windows', function() {93 var service = bridge.service('service1');94 var port = new MessageChannel().port1;95 fakeMessage.event.ports = [port];96 // Client 197 fakeMessage.data.originEnv = 'Window';98 service.emit('_connect', fakeMessage);99 sinon.assert.notCalled(fakeMessage.setSourcePort);100 // Client 2101 fakeMessage.data.clientId = 1234;102 fakeMessage.data.originEnv = 'Worker';103 service.emit('_connect', fakeMessage);104 sinon.assert.calledWith(fakeMessage.setSourcePort, port);105 });106 });...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run avocado automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful